xref: /haiku/src/add-ons/accelerants/radeon_hd/pll.cpp (revision c80809a3ab0b0a2ce53ea861a2b00ace24ff452d)
1 /*
2  * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Alexander von Gluck, kallisti5@unixzen.com
7  */
8 
9 
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
12 #include "utility.h"
13 #include "pll.h"
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19 
20 
21 #define TRACE_PLL
22 #ifdef TRACE_PLL
23 extern "C" void _sPrintf(const char *format, ...);
24 #   define TRACE(x...) _sPrintf("radeon_hd: " x)
25 #else
26 #   define TRACE(x...) ;
27 #endif
28 
29 
30 /* From hardcoded values. */
31 static struct PLL_Control RV610PLLControl[] =
32 {
33 	{ 0x0049, 0x159F8704 },
34 	{ 0x006C, 0x159B8704 },
35 	{ 0xFFFF, 0x159EC704 }
36 };
37 
38 /* Some tables are provided by atombios,
39  * it's just that they are hidden away deliberately and not exposed */
40 static struct PLL_Control RV670PLLControl[] =
41 {
42 	{ 0x004A, 0x159FC704 },
43 	{ 0x0067, 0x159BC704 },
44 	{ 0x00C4, 0x159EC704 },
45 	{ 0x00F4, 0x1593A704 },
46 	{ 0x0136, 0x1595A704 },
47 	{ 0x01A4, 0x1596A704 },
48 	{ 0x022C, 0x159CE504 },
49 	{ 0xFFFF, 0x1591E404 }
50 };
51 
52 
53 static uint32
54 PLLControlTable(struct PLL_Control *table, uint16 feedbackDivider)
55 {
56 	int i;
57 
58 	for (i = 0; table[i].feedbackDivider < 0xFFFF ; i++) {
59 		if (table[i].feedbackDivider >= feedbackDivider)
60 			break;
61 	}
62 
63 	return table[i].control;
64 }
65 
66 
67 status_t
68 PLLCalculate(uint32 pixelClock, uint16 *reference, uint16 *feedback,
69 	uint16 *post)
70 {
71 	// Freaking phase-locked loops, how do they work?
72 
73 	float ratio = ((float) pixelClock)
74 		/ ((float) gInfo->shared_info->pll_info.reference_frequency);
75 
76 	uint32 bestDiff = 0xFFFFFFFF;
77 	uint32 postDiv;
78 	uint32 referenceDiv;
79 	uint32 feedbackDiv;
80 
81 	for (postDiv = 2; postDiv < POST_DIV_LIMIT; postDiv++) {
82 		uint32 vcoOut = pixelClock * postDiv;
83 
84 		/* we are conservative and avoid the limits */
85 		if (vcoOut <= gInfo->shared_info->pll_info.min_frequency)
86 			continue;
87 		if (vcoOut >= gInfo->shared_info->pll_info.max_frequency)
88 			break;
89 
90 		for (referenceDiv = 1; referenceDiv <= REF_DIV_LIMIT; referenceDiv++) {
91 			feedbackDiv = (uint32)((ratio * postDiv * referenceDiv) + 0.5);
92 
93 			if (feedbackDiv >= FB_DIV_LIMIT)
94 				break;
95 			if (feedbackDiv > (500 + (13 * referenceDiv))) // rv6x0 limit
96 				break;
97 
98 			uint32 diff = abs(pixelClock - (feedbackDiv
99 					* gInfo->shared_info->pll_info.reference_frequency)
100 						/ (postDiv * referenceDiv));
101 
102 			if (diff < bestDiff) {
103 				*feedback = feedbackDiv;
104 				*reference = referenceDiv;
105 				*post = postDiv;
106 				bestDiff = diff;
107 			}
108 
109 			if (bestDiff == 0)
110 				break;
111 		}
112 
113 		if (bestDiff == 0)
114 			break;
115 	}
116 
117 	if (bestDiff != 0xFFFFFFFF) {
118 		TRACE("%s: Successful PLL Calculation: %dkHz = "
119 			"(((%i / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n", __func__,
120 			(int) pixelClock,
121 			(unsigned int) gInfo->shared_info->pll_info.reference_frequency,
122 			*reference, *feedback, *post, (int) bestDiff);
123 			return B_OK;
124 	}
125 
126 	// Shouldn't ever happen
127 	TRACE("%s: Failed to get a valid PLL setting for %dkHz\n",
128 		__func__, (int) pixelClock);
129 	return B_ERROR;
130 }
131 
132 
133 status_t
134 PLLPower(uint8 pllIndex, int command)
135 {
136 	uint16 pllControlReg = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
137 
138 	bool hasDccg = DCCGCLKAvailable(pllIndex);
139 
140 	TRACE("%s: card has DCCG = %c\n", __func__, hasDccg ? 'y' : 'n');
141 
142 	switch (command) {
143 		case RHD_POWER_ON:
144 		{
145 			TRACE("%s: PLL %d Power On\n", __func__, pllIndex);
146 
147 			if (hasDccg)
148 				DCCGCLKSet(pllIndex, RV620_DCCGCLK_RESET);
149 
150 			Write32Mask(PLL, pllControlReg, 0, 0x02);
151 				// Power On
152 			snooze(2);
153 			PLLCalibrate(pllIndex);
154 
155 			if (hasDccg)
156 				DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB);
157 
158 			return B_OK;
159 		}
160 		case RHD_POWER_RESET:
161 		{
162 			TRACE("%s: PLL %d Power Reset\n", __func__, pllIndex);
163 
164 			if (hasDccg)
165 				DCCGCLKSet(pllIndex, RV620_DCCGCLK_RELEASE);
166 
167 			Write32Mask(PLL, pllControlReg, 0x01, 0x01);
168 				// Reset
169 			snooze(2);
170 			Write32Mask(PLL, pllControlReg, 0, 0x02);
171 				// Power On
172 			snooze(2);
173 			return B_OK;
174 		}
175 
176 		case RHD_POWER_SHUTDOWN:
177 		default:
178 			TRACE("%s: PLL %d Power Shutdown\n", __func__, pllIndex);
179 
180 			radeon_shared_info &info = *gInfo->shared_info;
181 
182 			if (hasDccg)
183 				DCCGCLKSet(pllIndex, RV620_DCCGCLK_RELEASE);
184 
185 			Write32Mask(PLL, pllControlReg, 0x01, 0x01);
186 				// Reset
187 			snooze(2);
188 
189 			if (info.device_chipset >= (RADEON_R600 | 0x20)) {
190 				uint16 pllDiffPostReg
191 					= pllIndex == 1 ? RV620_EXT2_DIFF_POST_DIV_CNTL
192 						: RV620_EXT1_DIFF_POST_DIV_CNTL;
193 				uint16 pllDiffDriverEnable
194 					= pllIndex == 1 ? (uint16)RV62_EXT2_DIFF_DRIVER_ENABLE
195 						: (uint16)RV62_EXT1_DIFF_DRIVER_ENABLE;
196 
197 				// Sometimes we have to keep an unused PLL running. X Bug #18016
198 				if ((Read32(PLL, pllDiffPostReg)
199 					& pllDiffDriverEnable) == 0) {
200 					Write32Mask(PLL, pllControlReg, 0x02, 0x02);
201 						// Power Down
202 				} else {
203 					TRACE("%s: PHYA differential clock driver not disabled\n",
204 						__func__);
205 				}
206 
207 				snooze(200);
208 
209 				Write32Mask(PLL, pllControlReg,  0x2000, 0x2000);
210 					// Reset anti-glitch?
211 
212 			} else {
213 				Write32Mask(PLL, pllControlReg, 0x02, 0x02);
214 					// Power Down
215 				snooze(200);
216 			}
217 	}
218 
219 	return B_OK;
220 }
221 
222 
223 status_t
224 PLLSet(uint8 pllIndex, uint32 pixelClock)
225 {
226 	radeon_shared_info &info = *gInfo->shared_info;
227 
228 	uint16 reference = 0;
229 	uint16 feedback = 0;
230 	uint16 post = 0;
231 
232 	PLLCalculate(pixelClock, &reference, &feedback, &post);
233 
234 	if (info.device_chipset >= (RADEON_R600 | 0x20)) {
235 		TRACE("%s : setting pixel clock %d on r620+\n", __func__,
236 			(int)pixelClock);
237 		PLLSetLowR620(pllIndex, pixelClock, reference,
238 			feedback, post);
239 	} else if (info.device_chipset < (RADEON_R600 | 0x20)) {
240 		TRACE("%s : setting pixel clock %d on r600-r610\n", __func__,
241 			(int)pixelClock);
242 		PLLSetLowLegacy(pllIndex, pixelClock, reference,
243 			feedback, post);
244 	}
245 
246 	return B_OK;
247 }
248 
249 
250 void
251 PLLSetLowLegacy(uint8 pllIndex, uint32 pixelClock, uint16 reference,
252 	uint16 feedback, uint16 post)
253 {
254 	uint32 feedbackTemp = feedback << 16;
255 	uint32 referenceTemp = reference;
256 
257 	/* Internal PLL Registers */
258 	uint16 pllCntl = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
259 	uint16 pllIntSSCntl
260 		= pllIndex == 1 ? P2PLL_INT_SS_CNTL : P1PLL_INT_SS_CNTL;
261 
262 	/* External PLL Registers */
263 	uint16 pllExtCntl
264 		= pllIndex == 1 ? EXT2_PPLL_CNTL : EXT1_PPLL_CNTL;
265 	uint16 pllExtUpdateCntl
266 		= pllIndex == 1 ? EXT2_PPLL_UPDATE_CNTL : EXT1_PPLL_UPDATE_CNTL;
267 	uint16 pllExtUpdateLock
268 		= pllIndex == 1 ? EXT2_PPLL_UPDATE_LOCK : EXT1_PPLL_UPDATE_LOCK;
269 	uint16 pllExtPostDiv
270 		= pllIndex == 1 ? EXT2_PPLL_POST_DIV : EXT1_PPLL_POST_DIV;
271 	uint16 pllExtPostDivSrc
272 		= pllIndex == 1 ? EXT2_PPLL_POST_DIV_SRC : EXT1_PPLL_POST_DIV_SRC;
273 	uint16 pllExtFeedbackDiv
274 		= pllIndex == 1 ? EXT2_PPLL_FB_DIV : EXT1_PPLL_FB_DIV;
275 	uint16 pllExtRefDiv
276 		= pllIndex == 1 ? EXT2_PPLL_REF_DIV : EXT1_PPLL_REF_DIV;
277 	uint16 pllExtRefDivSrc
278 		= pllIndex == 1 ? EXT2_PPLL_REF_DIV_SRC : EXT1_PPLL_REF_DIV_SRC;
279 
280 	radeon_shared_info &info = *gInfo->shared_info;
281 
282 	if (info.device_chipset <= RADEON_R600)
283 		feedbackTemp |= 0x00000030;
284 	else {
285 		if (feedback <= 0x24)
286 			feedbackTemp |= 0x00000030;
287 		else if (feedback <= 0x3F)
288 			feedbackTemp |= 0x00000020;
289 	}
290 
291 	uint32 postTemp = Read32(PLL, pllExtPostDiv) & ~0x0000007F;
292 	postTemp |= post & 0x0000007F;
293 
294 	uint32 control;
295 	if (info.device_chipset == RADEON_R600)
296 		control = 0x01130704;
297 	else {
298 		control = PLLControlTable(RV610PLLControl, feedback);
299 		if (!control)
300 			control = Read32(PLL, pllExtCntl);
301 	}
302 
303 	Write32Mask(PLL, pllIntSSCntl, 0, 0x00000001);
304 		// Disable Spread Spectrum
305 
306 	Write32(PLL, pllExtRefDivSrc, 0x01); /* XTAL */
307 	Write32(PLL, pllExtPostDivSrc, 0x00); /* source = reference */
308 
309 	Write32(PLL, pllExtUpdateLock, 0x01); /* lock */
310 
311 	Write32(PLL, pllExtRefDiv, referenceTemp);
312 	Write32(PLL, pllExtFeedbackDiv, feedbackTemp);
313 	Write32(PLL, pllExtPostDiv, postTemp);
314 	Write32(PLL, pllExtCntl, control);
315 
316 	Write32Mask(PLL, pllExtUpdateCntl, 0x00010000, 0x00010000);
317 		// No autoreset
318 	Write32Mask(PLL, pllCntl, 0, 0x04);
319 		// Don't bypass calibration
320 
321 	/* We need to reset the anti glitch logic */
322 	Write32Mask(PLL, pllCntl, 0, 0x00000002);
323 		// Power up
324 
325 	/* reset anti glitch logic */
326 	Write32Mask(PLL, pllCntl, 0x00002000, 0x00002000);
327 	snooze(2);
328 	Write32Mask(PLL, pllCntl, 0, 0x00002000);
329 
330 	/* powerdown and reset */
331 	Write32Mask(PLL, pllCntl, 0x00000003, 0x00000003);
332 	snooze(2);
333 
334 	Write32(PLL, pllExtUpdateLock, 0);
335 		// Unlock
336 	Write32Mask(PLL, pllExtUpdateCntl, 0, 0x01);
337 		// Done updating
338 
339 	Write32Mask(PLL, pllCntl, 0, 0x02);
340 		// Power up PLL
341 	snooze(2);
342 
343 	PLLCalibrate(pllIndex);
344 
345 	Write32(PLL, pllExtPostDivSrc, 0x01);
346 		// Set source as PLL
347 
348 	// TODO : better way to grab crt to work on?
349 	PLLCRTCGrab(pllIndex, gRegister->crtid);
350 }
351 
352 
353 void
354 PLLSetLowR620(uint8 pllIndex, uint32 pixelClock, uint16 reference,
355 	uint16 feedback, uint16 post)
356 {
357 	radeon_shared_info &info = *gInfo->shared_info;
358 
359 	bool hasDccg = DCCGCLKAvailable(pllIndex);
360 
361 	TRACE("%s: card has DCCG = %c\n", __func__, hasDccg ? 'y' : 'n');
362 
363 	if (hasDccg)
364 		DCCGCLKSet(pllIndex, RV620_DCCGCLK_RESET);
365 
366 	/* Internal PLL Registers */
367 	uint16 pllCntl = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
368 	uint16 pllIntSSCntl
369 		= pllIndex == 1 ? P2PLL_INT_SS_CNTL : P1PLL_INT_SS_CNTL;
370 
371 	/* External PLL Registers */
372 	uint16 pllExtCntl
373 		= pllIndex == 1 ? EXT2_PPLL_CNTL : EXT1_PPLL_CNTL;
374 	//uint16 pllExtUpdateCntl
375 	//	= pllIndex == 1 ? EXT2_PPLL_UPDATE_CNTL : EXT1_PPLL_UPDATE_CNTL;
376 	uint16 pllExtUpdateLock
377 		= pllIndex == 1 ? EXT2_PPLL_UPDATE_LOCK : EXT1_PPLL_UPDATE_LOCK;
378 	uint16 pllExtPostDiv
379 		= pllIndex == 1 ? EXT2_PPLL_POST_DIV : EXT1_PPLL_POST_DIV;
380 	uint16 pllExtPostDivSrc
381 		= pllIndex == 1 ? EXT2_PPLL_POST_DIV_SRC : EXT1_PPLL_POST_DIV_SRC;
382 	uint16 pllExtPostDivSym
383 		= pllIndex == 1 ? EXT2_SYM_PPLL_POST_DIV : EXT1_SYM_PPLL_POST_DIV;
384 	uint16 pllExtFeedbackDiv
385 		= pllIndex == 1 ? EXT2_PPLL_FB_DIV : EXT1_PPLL_FB_DIV;
386 	uint16 pllExtRefDiv
387 		= pllIndex == 1 ? EXT2_PPLL_REF_DIV : EXT1_PPLL_REF_DIV;
388 	//uint16 pllExtRefDivSrc
389 	//	= pllIndex == 1 ? EXT2_PPLL_REF_DIV_SRC : EXT1_PPLL_REF_DIV_SRC;
390 	uint16 pllExtDispClkCntl
391 		= pllIndex == 1 ? P2PLL_DISP_CLK_CNTL : P1PLL_DISP_CLK_CNTL;
392 
393 	Write32Mask(PLL, pllIntSSCntl, 0, 0x00000001);
394 		// Disable Spread Spectrum
395 
396 	uint32 referenceDivider = reference;
397 
398 	uint32 feedbackDivider = Read32(PLL, pllExtFeedbackDiv) & ~0x07FF003F;
399 	feedbackDivider |= ((feedback << 16) | 0x0030) & 0x07FF003F;
400 
401 	uint32 postDivider = Read32(PLL, pllExtPostDiv) & ~0x0000007F;
402 	postDivider |= post & 0x0000007F;
403 
404 	uint32 control;
405 
406 	if (info.device_chipset >= (RADEON_R600 | 0x70))
407 		control = PLLControlTable(RV670PLLControl, feedback);
408 	else
409 		control = PLLControlTable(RV610PLLControl, feedback);
410 
411 	uint8 symPostDiv = post & 0x0000007F;
412 
413 	/* switch to external */
414 	Write32(PLL, pllExtPostDivSrc, 0);
415 	Write32Mask(PLL, pllExtDispClkCntl, 0x00000200, 0x00000300);
416 	Write32Mask(PLL, pllExtPostDiv, 0, 0x00000100);
417 
418 	Write32Mask(PLL, pllCntl, 0x00000001, 0x00000001);
419 		// reset
420 	snooze(2);
421 	Write32Mask(PLL, pllCntl, 0x00000002, 0x00000002);
422 		// power down
423 	snooze(10);
424 	Write32Mask(PLL, pllCntl, 0x00002000, 0x00002000);
425 		// reset antiglitch
426 
427 	Write32(PLL, pllExtCntl, control);
428 
429 	Write32Mask(PLL, pllExtDispClkCntl, 2, 0x0000003F);
430 		// Scalar Divider 2
431 
432 	Write32(PLL, pllExtUpdateLock, 1);
433 		// Lock PLL
434 
435 	/* Write PLL clocks */
436 	Write32(PLL, pllExtPostDivSrc, 0x00000001);
437 	Write32(PLL, pllExtRefDiv, referenceDivider);
438 	Write32(PLL, pllExtFeedbackDiv, feedbackDivider);
439 	Write32Mask(PLL, pllExtPostDiv, postDivider, 0x0000007F);
440 	Write32Mask(PLL, pllExtPostDivSym, symPostDiv, 0x0000007F);
441 
442 	snooze(10);
443 
444 	Write32(PLL, pllExtUpdateLock, 0);
445 		// Unlock PLL
446 
447 	Write32Mask(PLL, pllCntl, 0, 0x00000002);
448 		// power up
449 	snooze(10);
450 
451 	Write32Mask(PLL, pllCntl, 0, 0x00002000);
452 		// undo reset antiglitch
453 
454 	PLLCalibrate(pllIndex);
455 
456 	/* Switch back to PLL */
457 	Write32Mask(PLL, pllExtDispClkCntl, 0, 0x00000300);
458 	Write32Mask(PLL, pllExtPostDivSym, 0x00000100, 0x00000100);
459 	Write32(PLL, pllExtPostDivSrc, 0x00000001);
460 
461 	Write32Mask(PLL, pllCntl, 0, 0x80000000);
462 		// needed and undocumented
463 
464 	// TODO : better way to grab crt to work on?
465 	PLLCRTCGrab(pllIndex, gRegister->crtid);
466 
467 	if (hasDccg)
468 		DCCGCLKSet(pllIndex, RV620_DCCGCLK_GRAB);
469 
470 	TRACE("%s: PLLSet exit\n", __func__);
471 }
472 
473 
474 status_t
475 PLLCalibrate(uint8 pllIndex)
476 {
477 	uint16 pllControlReg = pllIndex == 1 ? P2PLL_CNTL : P1PLL_CNTL;
478 
479 	Write32Mask(PLL, pllControlReg, 1, 0x01);
480 		// PLL Reset
481 
482 	snooze(2);
483 
484 	Write32Mask(PLL, pllControlReg, 0, 0x01);
485 		// PLL Set
486 
487 	int i;
488 
489 	for (i = 0; i < PLL_CALIBRATE_WAIT; i++) {
490 		if (((Read32(PLL, pllControlReg) >> 20) & 0x03) == 0x03)
491 			break;
492 	}
493 
494 	if (i >= PLL_CALIBRATE_WAIT) {
495 		if (Read32(PLL, pllControlReg) & 0x00100000) /* Calibration done? */
496 			TRACE("%s: Calibration Failed\n", __func__);
497 		if (Read32(PLL, pllControlReg) & 0x00200000) /* PLL locked? */
498 			TRACE("%s: Locking Failed\n", __func__);
499 		TRACE("%s: We encountered a problem calibrating the PLL.\n", __func__);
500 		return B_ERROR;
501 	} else
502 		TRACE("%s: pll calibrated and locked in %d loops\n", __func__, i);
503 
504 	return B_OK;
505 }
506 
507 
508 void
509 PLLCRTCGrab(uint8 pllIndex, uint8 crtid)
510 {
511 	bool pll2IsCurrent;
512 
513 	if (crtid == 0) {
514 		pll2IsCurrent = Read32(PLL, PCLK_CRTC1_CNTL) & 0x00010000;
515 
516 		Write32Mask(PLL, PCLK_CRTC1_CNTL, pllIndex == 0 ? 0x00010000 : 0,
517 			0x00010000);
518 	} else {
519 		pll2IsCurrent = Read32(PLL, PCLK_CRTC2_CNTL) & 0x00010000;
520 
521 		Write32Mask(PLL, PCLK_CRTC2_CNTL, pllIndex == 0 ? 0x00010000 : 0,
522 			0x00010000);
523 	}
524 
525 	/* if the current pll is not active, then poke it just enough to flip
526 	* owners */
527 	if (!pll2IsCurrent) {
528 		uint32 stored = Read32(PLL, P1PLL_CNTL);
529 
530 		if (stored & 0x03) {
531 			Write32Mask(PLL, P1PLL_CNTL, 0, 0x03);
532 			snooze(10);
533 			Write32Mask(PLL, P1PLL_CNTL, stored, 0x03);
534 		}
535 
536 	} else {
537 		uint32 stored = Read32(PLL, P2PLL_CNTL);
538 
539 		if (stored & 0x03) {
540 			Write32Mask(PLL, P2PLL_CNTL, 0, 0x03);
541 			snooze(10);
542 			Write32Mask(PLL, P2PLL_CNTL, stored, 0x03);
543 		}
544 	}
545 }
546 
547 
548 // See if card has a DCCG available that we need to lock to
549 // the PLL clock. No one seems really sure what DCCG is.
550 bool
551 DCCGCLKAvailable(uint8 pllIndex)
552 {
553 	radeon_shared_info &info = *gInfo->shared_info;
554 
555 	if (info.device_chipset < (RADEON_R600 | 0x20))
556 		return false;
557 
558 	uint32 dccg = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
559 
560 	if (dccg & 0x02)
561 		return true;
562 
563 	if ((pllIndex == 0) && (dccg == 0))
564 		return true;
565 	if ((pllIndex == 1) && (dccg == 1))
566 		return true;
567 
568 	return false;
569 }
570 
571 
572 void
573 DCCGCLKSet(uint8 pllIndex, int set)
574 {
575 	uint32 buffer;
576 
577 	switch(set) {
578 		case RV620_DCCGCLK_GRAB:
579 			if (pllIndex == 0)
580 				Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
581 			else if (pllIndex == 1)
582 				Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
583 			else
584 				Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
585 			break;
586 		case RV620_DCCGCLK_RELEASE:
587 			buffer = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
588 
589 			if ((pllIndex == 0) && (buffer == 0)) {
590 				/* set to other PLL or external */
591 				buffer = Read32(PLL, P2PLL_CNTL);
592 				// if powered and not in reset, and calibrated and locked
593 				if (!(buffer & 0x03) && ((buffer & 0x00300000) == 0x00300000))
594 					Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
595 				else
596 					Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
597 
598 			} else if ((pllIndex == 1) && (buffer == 1)) {
599 				/* set to other PLL or external */
600 				buffer = Read32(PLL, P1PLL_CNTL);
601 				// if powered and not in reset, and calibrated and locked
602 				if (!(buffer & 0x03) && ((buffer & 0x00300000) == 0x00300000))
603 					Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
604 				else
605 					Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
606 
607 			} // no other action needed
608 			break;
609 		case RV620_DCCGCLK_RESET:
610 			buffer = Read32(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
611 
612 			if (((pllIndex == 0) && (buffer == 0))
613 				|| ((pllIndex == 1) && (buffer == 1)))
614 				Write32Mask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
615 			break;
616 		default:
617 			break;
618 	}
619 }
620 
621