Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1029 serge 1
/*
2
 * Copyright 2007  Luc Verhaegen 
3
 * Copyright 2007  Matthias Hopf 
4
 * Copyright 2007  Egbert Eich   
5
 * Copyright 2007  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_regs.h"
43
#include "rhd_atombios.h"
44
 
45
 
46
#define PLL_CALIBRATE_WAIT 0x100000
47
 
48
/*
49
 * Get gain, charge pump, loop filter and current bias.
50
 * For R500, this is done in atombios by ASIC_RegistersInit
51
 * Some data table in atom should've provided this information.
52
 */
53
 
54
struct PLL_Control {
55
    CARD16 FeedbackDivider; /* 0xFFFF/-1 is the endmarker here */
56
    CARD32 Control;
57
};
58
 
59
/* From hardcoded values. */
60
static struct PLL_Control RV610PLLControl[] =
61
{
62
    { 0x0049, 0x159F8704 },
63
    { 0x006C, 0x159B8704 },
64
    { 0xFFFF, 0x159EC704 }
65
};
66
 
67
/* Some tables are provided by atombios,
68
 * it's just that they are hidden away deliberately and not exposed */
69
static struct PLL_Control RV670PLLControl[] =
70
{
71
    { 0x004A, 0x159FC704 },
72
    { 0x0067, 0x159BC704 },
73
    { 0x00C4, 0x159EC704 },
74
    { 0x00F4, 0x1593A704 },
75
    { 0x0136, 0x1595A704 },
76
    { 0x01A4, 0x1596A704 },
77
    { 0x022C, 0x159CE504 },
78
    { 0xFFFF, 0x1591E404 }
79
};
80
 
81
/*
82
 * Used by PLLElectrical() for r5xx+ and by rv620/35 code.
83
 */
84
static CARD32
85
PLLControlTableRetrieve(struct PLL_Control *Table, CARD16 FeedbackDivider)
86
{
87
    int i;
88
 
89
    for (i = 0; Table[i].FeedbackDivider < 0xFFFF ; i++)
90
	if (Table[i].FeedbackDivider >= FeedbackDivider)
91
	    break;
92
 
93
    return Table[i].Control;
94
}
95
 
96
/*
97
 * Not used by rv620/35 code.
98
 */
99
static CARD32
100
PLLElectrical(RHDPtr rhdPtr, CARD16 FeedbackDivider)
101
{
102
    switch (rhdPtr->ChipSet) {
103
    case RHD_RV515:
104
	if (rhdPtr->PciDeviceID == 0x7146)
105
	    return 0x00120704;
106
	else
107
	    return 0;
108
    case RHD_RV535:
109
	if (rhdPtr->PciDeviceID == 0x71C1)
110
	    return 0x00230704;
111
	else
112
	    return 0;
113
    case RHD_RS600:
114
    case RHD_RS690:
115
    case RHD_RS740:
116
	/* depending on MiscInfo also 0x00120004 */
117
	return 0x00120704;
118
    case RHD_R600:
119
	return 0x01130704;
120
    case RHD_RV610:
121
    case RHD_RV630:
122
    case RHD_M72:
123
    case RHD_M74:
124
    case RHD_M76:
125
	return PLLControlTableRetrieve(RV610PLLControl, FeedbackDivider);
126
    case RHD_RV670:
127
    case RHD_R680:
128
	return PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider);
129
    default:
130
	return 0;
131
    }
132
}
133
 
134
/*
135
 * All R500s, RS6x0, R600, RV610 and RV630.
136
 */
137
 
138
/*
139
 *
140
 */
141
static void
142
PLL1Calibrate(struct rhdPLL *PLL)
143
{
144
    int i;
145
 
146
    RHDFUNC(PLL);
147
 
148
    RHDRegMask(PLL, P1PLL_CNTL, 1, 0x01); /* Reset */
149
    usleep(2);
150
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x01); /* Set */
151
    for (i = 0; i < PLL_CALIBRATE_WAIT; i++)
152
	if (((RHDRegRead(PLL, P1PLL_CNTL) >> 20) & 0x03) == 0x03)
153
	    break;
154
 
155
    if (i == PLL_CALIBRATE_WAIT) {
156
	if (RHDRegRead(PLL, P1PLL_CNTL) & 0x00100000) /* Calibration done? */
157
	    xf86DrvMsg(PLL->scrnIndex, X_ERROR,
158
		       "%s: Calibration failed.\n", __func__);
159
	if (RHDRegRead(PLL, P1PLL_CNTL) & 0x00200000) /* PLL locked? */
160
	    xf86DrvMsg(PLL->scrnIndex, X_ERROR,
161
		       "%s: Locking failed.\n", __func__);
162
    } else
163
	RHDDebug(PLL->scrnIndex, "%s: lock in %d loops\n", __func__, i);
164
}
165
 
166
/*
167
 *
168
 */
169
static void
170
PLL2Calibrate(struct rhdPLL *PLL)
171
{
172
    int i;
173
 
174
    RHDFUNC(PLL);
175
 
176
    RHDRegMask(PLL, P2PLL_CNTL, 1, 0x01); /* Reset */
177
    usleep(2);
178
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x01); /* Set */
179
 
180
    for (i = 0; i < PLL_CALIBRATE_WAIT; i++)
181
	if (((RHDRegRead(PLL, P2PLL_CNTL) >> 20) & 0x03) == 0x03)
182
	    break;
183
 
184
    if (i == PLL_CALIBRATE_WAIT) {
185
	if (RHDRegRead(PLL, P2PLL_CNTL) & 0x00100000) /* Calibration done? */
186
	    xf86DrvMsg(PLL->scrnIndex, X_ERROR,
187
		       "%s: Calibration failed.\n", __func__);
188
	if (RHDRegRead(PLL, P2PLL_CNTL) & 0x00200000) /* PLL locked? */
189
	    xf86DrvMsg(PLL->scrnIndex, X_ERROR,
190
		       "%s: Locking failed.\n", __func__);
191
    } else
192
	RHDDebug(PLL->scrnIndex, "%s: lock in %d loops\n", __func__, i);
193
}
194
 
195
/*
196
 *
197
 */
198
static void
199
R500PLL1Power(struct rhdPLL *PLL, int Power)
200
{
201
    RHDFUNC(PLL);
202
 
203
    switch (Power) {
204
    case RHD_POWER_ON:
205
	RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */
206
	usleep(2);
207
 
208
	PLL1Calibrate(PLL);
209
 
210
	return;
211
    case RHD_POWER_RESET:
212
	RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */
213
	usleep(2);
214
 
215
	RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */
216
	usleep(2);
217
 
218
	return;
219
    case RHD_POWER_SHUTDOWN:
220
    default:
221
	RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */
222
	usleep(2);
223
 
224
	RHDRegMask(PLL, P1PLL_CNTL, 0x02, 0x02); /* Power down */
225
	usleep(200);
226
 
227
	return;
228
    }
229
}
230
 
231
/*
232
 *
233
 */
234
static void
235
R500PLL2Power(struct rhdPLL *PLL, int Power)
236
{
237
    RHDFUNC(PLL);
238
 
239
    switch (Power) {
240
    case RHD_POWER_ON:
241
	RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */
242
	usleep(2);
243
 
244
	PLL2Calibrate(PLL);
245
 
246
	return;
247
    case RHD_POWER_RESET:
248
	RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */
249
	usleep(2);
250
 
251
	RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */
252
	usleep(2);
253
 
254
	return;
255
    case RHD_POWER_SHUTDOWN:
256
    default:
257
	RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */
258
	usleep(2);
259
 
260
	RHDRegMask(PLL, P2PLL_CNTL, 0x02, 0x02); /* Power down */
261
	usleep(200);
262
 
263
	return;
264
    }
265
}
266
 
267
/*
268
 *
269
 */
270
static void
271
R500PLL1SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv,
272
	       CARD32 Control)
273
{
274
    RHDFUNC(PLL);
275
    RHDRegWrite(PLL, EXT1_PPLL_REF_DIV_SRC, 0x01); /* XTAL */
276
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00); /* source = reference */
277
 
278
    RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0x01); /* lock */
279
 
280
    RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, RefDiv);
281
    RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, FBDiv);
282
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PostDiv);
283
    RHDRegWrite(PLL, EXT1_PPLL_CNTL, Control);
284
 
285
    RHDRegMask(PLL, EXT1_PPLL_UPDATE_CNTL, 0x00010000, 0x00010000); /* no autoreset */
286
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x04); /* don't bypass calibration */
287
 
288
    /* We need to reset the anti glitch logic */
289
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00000002); /* power up */
290
 
291
    /* reset anti glitch logic */
292
    RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000);
293
    usleep(2);
294
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000);
295
 
296
    /* powerdown and reset */
297
    RHDRegMask(PLL, P1PLL_CNTL, 0x00000003, 0x00000003);
298
    usleep(2);
299
 
300
    RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0); /* unlock */
301
    RHDRegMask(PLL, EXT1_PPLL_UPDATE_CNTL, 0, 0x01); /* we're done updating! */
302
 
303
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */
304
    usleep(2);
305
 
306
    PLL1Calibrate(PLL);
307
 
308
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x01); /* source is PLL itself */
309
}
310
 
311
/*
312
 *
313
 */
314
static void
315
R500PLL2SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv,
316
	       CARD32 Control)
317
{
318
    RHDRegWrite(PLL, EXT2_PPLL_REF_DIV_SRC, 0x01); /* XTAL */
319
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00); /* source = reference */
320
 
321
    RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0x01); /* lock */
322
 
323
    RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, RefDiv);
324
    RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, FBDiv);
325
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PostDiv);
326
    RHDRegWrite(PLL, EXT2_PPLL_CNTL, Control);
327
 
328
    RHDRegMask(PLL, EXT2_PPLL_UPDATE_CNTL, 0x00010000, 0x00010000); /* no autoreset */
329
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x04); /* don't bypass calibration */
330
 
331
    /* We need to reset the anti glitch logic */
332
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00000002); /* power up */
333
 
334
    /* reset anti glitch logic */
335
    RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000);
336
    usleep(2);
337
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000);
338
 
339
    /* powerdown and reset */
340
    RHDRegMask(PLL, P2PLL_CNTL, 0x00000003, 0x00000003);
341
    usleep(2);
342
 
343
    RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0); /* unlock */
344
    RHDRegMask(PLL, EXT2_PPLL_UPDATE_CNTL, 0, 0x01); /* we're done updating! */
345
 
346
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */
347
    usleep(2);
348
 
349
    PLL2Calibrate(PLL);
350
 
351
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x01); /* source is PLL itself */
352
}
353
 
354
/*
355
 * The CRTC ownership of each PLL is multiplexed on the PLL blocks, and the
356
 * ownership can only be switched when the currently referenced PLL is active.
357
 * This makes handling a slight bit more complex.
358
 */
359
static void
360
R500PLLCRTCGrab(struct rhdPLL *PLL, Bool Crtc2)
361
{
362
    CARD32 Stored;
363
    Bool PLL2IsCurrent;
364
 
365
    if (!Crtc2) {
366
	PLL2IsCurrent = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000;
367
 
368
	if (PLL->Id == PLL_ID_PLL1)
369
	    RHDRegMask(PLL, PCLK_CRTC1_CNTL, 0, 0x00010000);
370
	else
371
	    RHDRegMask(PLL, PCLK_CRTC1_CNTL, 0x00010000, 0x00010000);
372
    } else {
373
	PLL2IsCurrent = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000;
374
 
375
	if (PLL->Id == PLL_ID_PLL1)
376
	    RHDRegMask(PLL, PCLK_CRTC2_CNTL, 0, 0x00010000);
377
	else
378
	    RHDRegMask(PLL, PCLK_CRTC2_CNTL, 0x00010000, 0x00010000);
379
    }
380
 
381
    /* if the current pll is not active, then poke it just enough to flip
382
     * owners */
383
    if (!PLL2IsCurrent) {
384
	Stored = RHDRegRead(PLL, P1PLL_CNTL);
385
 
386
	if (Stored & 0x03) {
387
	    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x03);
388
	    usleep(10);
389
	    RHDRegMask(PLL, P1PLL_CNTL, Stored, 0x03);
390
	}
391
    } else {
392
	Stored = RHDRegRead(PLL, P2PLL_CNTL);
393
 
394
	if (Stored & 0x03) {
395
	    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x03);
396
	    usleep(10);
397
	    RHDRegMask(PLL, P2PLL_CNTL, Stored, 0x03);
398
	}
399
    }
400
}
401
 
402
/*
403
 *
404
 */
405
static void
406
R500PLL1Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider,
407
	    CARD16 FeedbackDivider, CARD8 PostDivider)
408
{
409
    RHDPtr rhdPtr = RHDPTRI(PLL);
410
    CARD32 RefDiv, FBDiv, PostDiv, Control;
411
 
412
    RHDFUNC(PLL);
413
 
414
    RefDiv = ReferenceDivider;
415
 
416
    FBDiv = FeedbackDivider << 16;
417
 
418
    if (rhdPtr->ChipSet > RHD_R600) { /* set up Feedbackdivider slip */
419
	if (FeedbackDivider <= 0x24)
420
	    FBDiv |= 0x00000030;
421
	else if (FeedbackDivider <= 0x3F)
422
	    FBDiv |= 0x00000020;
423
    } else if (rhdPtr->ChipSet >= RHD_RS600) /* RS600, RS690, R600 */
424
	FBDiv |= 0x00000030;
425
    else
426
	FBDiv |= RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & 0x00000030;
427
 
428
    PostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & ~0x0000007F;
429
    PostDiv |= PostDivider & 0x0000007F;
430
 
431
    Control = PLLElectrical(rhdPtr, FeedbackDivider);
432
    if (!Control)
433
	Control = RHDRegRead(PLL, EXT1_PPLL_CNTL);
434
 
435
    /* Disable Spread Spectrum */
436
    RHDRegMask(PLL, P1PLL_INT_SS_CNTL, 0, 0x00000001);
437
 
438
    R500PLL1SetLow(PLL, RefDiv, FBDiv, PostDiv, Control);
439
 
440
    if (rhdPtr->Crtc[0]->PLL == PLL)
441
	R500PLLCRTCGrab(PLL, FALSE);
442
    if (rhdPtr->Crtc[1]->PLL == PLL)
443
	R500PLLCRTCGrab(PLL, TRUE);
444
}
445
 
446
/*
447
 *
448
 */
449
static void
450
R500PLL2Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider,
451
	    CARD16 FeedbackDivider, CARD8 PostDivider)
452
{
453
    RHDPtr rhdPtr = RHDPTRI(PLL);
454
    CARD32 RefDiv, FBDiv, PostDiv, Control;
455
 
456
    RHDFUNC(PLL);
457
 
458
    RefDiv = ReferenceDivider;
459
 
460
    FBDiv = FeedbackDivider << 16;
461
 
462
    if (rhdPtr->ChipSet > RHD_R600) { /* set up Feedbackdivider slip */
463
	if (FeedbackDivider <= 0x24)
464
	    FBDiv |= 0x00000030;
465
	else if (FeedbackDivider <= 0x3F)
466
	    FBDiv |= 0x00000020;
467
    } else if (rhdPtr->ChipSet >= RHD_RS600) /* RS600, RS690, R600 */
468
	FBDiv |= 0x00000030;
469
    else
470
	FBDiv |= RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & 0x00000030;
471
 
472
    PostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & ~0x0000007F;
473
    PostDiv |= PostDivider & 0x0000007F;
474
 
475
    Control = PLLElectrical(rhdPtr, FeedbackDivider);
476
    if (!Control)
477
	Control = RHDRegRead(PLL, EXT2_PPLL_CNTL);
478
 
479
    /* Disable Spread Spectrum */
480
    RHDRegMask(PLL, P2PLL_INT_SS_CNTL, 0, 0x00000001);
481
 
482
    R500PLL2SetLow(PLL, RefDiv, FBDiv, PostDiv, Control);
483
 
484
    if (rhdPtr->Crtc[0]->PLL == PLL)
485
	R500PLLCRTCGrab(PLL, FALSE);
486
    if (rhdPtr->Crtc[1]->PLL == PLL)
487
	R500PLLCRTCGrab(PLL, TRUE);
488
}
489
 
490
/*
491
 *
492
 */
493
static void
494
R500PLL1Save(struct rhdPLL *PLL)
495
{
496
    RHDFUNC(PLL);
497
 
498
    PLL->StoreActive = !(RHDRegRead(PLL, P1PLL_CNTL) & 0x03);
499
    PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV);
500
    PLL->StoreFBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV);
501
    PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV);
502
    PLL->StoreControl = RHDRegRead(PLL, EXT1_PPLL_CNTL);
503
    PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL);
504
    PLL->StoreCrtc1Owner = !(RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000);
505
    PLL->StoreCrtc2Owner = !(RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000);
506
 
507
    PLL->Stored = TRUE;
508
}
509
 
510
/*
511
 *
512
 */
513
static void
514
R500PLL2Save(struct rhdPLL *PLL)
515
{
516
    RHDFUNC(PLL);
517
 
518
    PLL->StoreActive = !(RHDRegRead(PLL, P2PLL_CNTL) & 0x03);
519
    PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV);
520
    PLL->StoreFBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV);
521
    PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV);
522
    PLL->StoreControl = RHDRegRead(PLL, EXT2_PPLL_CNTL);
523
    PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL);
524
    PLL->StoreCrtc1Owner = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000;
525
    PLL->StoreCrtc2Owner = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000;
526
 
527
    PLL->Stored = TRUE;
528
}
529
 
530
/*
531
 *
532
 */
533
static void
534
R500PLL1Restore(struct rhdPLL *PLL)
535
{
536
    RHDFUNC(PLL);
537
 
538
    if (!PLL->Stored) {
539
	xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore "
540
		   "uninitialized values.\n", __func__, PLL->Name);
541
	return;
542
    }
543
 
544
    if (PLL->StoreActive) {
545
	R500PLL1SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv,
546
		       PLL->StorePostDiv, PLL->StoreControl);
547
 
548
	/* HotFix: always keep spread spectrum disabled on restore */
549
	if (0 && RHDPTRI(PLL)->ChipSet != RHD_M54)
550
	    RHDRegMask(PLL, P1PLL_INT_SS_CNTL,
551
		       PLL->StoreSpreadSpectrum, 0x00000001);
552
    } else {
553
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
554
 
555
	/* lame attempt at at least restoring the old values */
556
	RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, PLL->StoreRefDiv);
557
	RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, PLL->StoreFBDiv);
558
	RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PLL->StorePostDiv);
559
	RHDRegWrite(PLL, EXT1_PPLL_CNTL, PLL->StoreControl);
560
	RHDRegWrite(PLL, P1PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum);
561
    }
562
 
563
    if (PLL->StoreCrtc1Owner)
564
	R500PLLCRTCGrab(PLL, FALSE);
565
    if (PLL->StoreCrtc2Owner)
566
	R500PLLCRTCGrab(PLL, TRUE);
567
}
568
 
569
/*
570
 *
571
 */
572
static void
573
R500PLL2Restore(struct rhdPLL *PLL)
574
{
575
    RHDFUNC(PLL);
576
 
577
    if (!PLL->Stored) {
578
	xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore "
579
		   "uninitialized values.\n", __func__, PLL->Name);
580
	return;
581
    }
582
 
583
    if (PLL->StoreActive) {
584
	R500PLL2SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv,
585
		       PLL->StorePostDiv, PLL->StoreControl);
586
 
587
	if (RHDPTRI(PLL)->ChipSet != RHD_M54)
588
	    RHDRegMask(PLL, P2PLL_INT_SS_CNTL,
589
		       PLL->StoreSpreadSpectrum, 0x00000001);
590
    } else {
591
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
592
 
593
	/* lame attempt at at least restoring the old values */
594
	RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, PLL->StoreRefDiv);
595
	RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, PLL->StoreFBDiv);
596
	RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PLL->StorePostDiv);
597
	RHDRegWrite(PLL, EXT2_PPLL_CNTL, PLL->StoreControl);
598
	RHDRegWrite(PLL, P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum);
599
    }
600
 
601
    if (PLL->StoreCrtc1Owner)
602
	R500PLLCRTCGrab(PLL, FALSE);
603
    if (PLL->StoreCrtc2Owner)
604
	R500PLLCRTCGrab(PLL, TRUE);
605
}
606
 
607
/*
608
 * RV620 and up
609
 */
610
 
611
/*
612
 *
613
 */
614
#define RV620_DCCGCLK_RESET   0
615
#define RV620_DCCGCLK_GRAB    1
616
#define RV620_DCCGCLK_RELEASE 2
617
 
618
/*
619
 * I still have no idea what DCCG stands for and why it needs to hook off some
620
 * pixelclock...
621
 */
622
static void
623
RV620DCCGCLKSet(struct rhdPLL *PLL, int set)
624
{
625
    CARD32 tmp;
626
 
627
    RHDFUNC(PLL);
628
 
629
    switch(set) {
630
    case RV620_DCCGCLK_GRAB:
631
	if (PLL->Id == PLL_ID_PLL1)
632
	    RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
633
	else if (PLL->Id == PLL_ID_PLL2)
634
	    RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
635
	else
636
	    RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
637
	break;
638
    case RV620_DCCGCLK_RELEASE:
639
	tmp = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
640
 
641
	if ((PLL->Id == PLL_ID_PLL1) && (tmp == 0)) {
642
	    /* set to other PLL or external */
643
	    tmp = RHDRegRead(PLL, P2PLL_CNTL);
644
	    if (!(tmp & 0x03) && /* powered and not in reset */
645
		((tmp & 0x00300000) == 0x00300000)) /* calibrated and locked */
646
		RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003);
647
	    else
648
		RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
649
	} else if ((PLL->Id == PLL_ID_PLL2) && (tmp == 1)) {
650
	    /* set to other PLL or external */
651
	    tmp = RHDRegRead(PLL, P1PLL_CNTL);
652
	    if (!(tmp & 0x03) && /* powered and not in reset */
653
		((tmp & 0x00300000) == 0x00300000)) /* calibrated and locked */
654
		RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003);
655
	    else
656
		RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
657
 
658
	} /* no other action needs to be taken */
659
	break;
660
    case RV620_DCCGCLK_RESET:
661
	tmp = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
662
 
663
	if (((PLL->Id == PLL_ID_PLL1) && (tmp == 0)) ||
664
	    ((PLL->Id == PLL_ID_PLL2) && (tmp == 1)))
665
	    RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003);
666
	break;
667
    default:
668
	break;
669
    }
670
}
671
 
672
/*
673
 *
674
 */
675
static Bool
676
RV620DCCGCLKAvailable(struct rhdPLL *PLL)
677
{
678
    CARD32 Dccg = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03;
679
 
680
    RHDFUNC(PLL);
681
 
682
    if (Dccg & 0x02)
683
	return TRUE;
684
 
685
    if ((PLL->Id == PLL_ID_PLL1) && (Dccg == 0))
686
	return TRUE;
687
    if ((PLL->Id == PLL_ID_PLL2) && (Dccg == 1))
688
	return TRUE;
689
 
690
    return FALSE;
691
}
692
 
693
/*
694
 *
695
 */
696
static void
697
RV620PLL1Power(struct rhdPLL *PLL, int Power)
698
{
699
    RHDFUNC(PLL);
700
 
701
    switch (Power) {
702
    case RHD_POWER_ON:
703
    {
704
	Bool HasDccg = RV620DCCGCLKAvailable(PLL);
705
 
706
	if (HasDccg)
707
	    RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET);
708
 
709
	RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */
710
	usleep(2);
711
 
712
	PLL1Calibrate(PLL);
713
 
714
	if (HasDccg)
715
	    RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB);
716
	return;
717
    }
718
    case RHD_POWER_RESET:
719
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE);
720
 
721
	RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */
722
	usleep(2);
723
 
724
	RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */
725
	usleep(2);
726
 
727
	return;
728
    case RHD_POWER_SHUTDOWN:
729
    default:
730
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE);
731
 
732
	RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */
733
	usleep(2);
734
 
735
	RHDRegMask(PLL, P1PLL_CNTL, 0x02, 0x02); /* Power down */
736
	usleep(200);
737
 
738
	return;
739
    }
740
}
741
 
742
/*
743
 *
744
 */
745
static void
746
RV620PLL2Power(struct rhdPLL *PLL, int Power)
747
{
748
    RHDFUNC(PLL);
749
 
750
    switch (Power) {
751
    case RHD_POWER_ON:
752
    {
753
	Bool HasDccg = RV620DCCGCLKAvailable(PLL);
754
 
755
	if (HasDccg)
756
	    RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET);
757
 
758
	RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */
759
	usleep(2);
760
 
761
	PLL2Calibrate(PLL);
762
 
763
	if (HasDccg)
764
	    RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB);
765
	return;
766
    }
767
    case RHD_POWER_RESET:
768
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE);
769
 
770
	RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */
771
	usleep(2);
772
 
773
	RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */
774
	usleep(2);
775
 
776
	return;
777
    case RHD_POWER_SHUTDOWN:
778
    default:
779
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE);
780
 
781
	RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */
782
	usleep(2);
783
 
784
	RHDRegMask(PLL, P2PLL_CNTL, 0x02, 0x02); /* Power down */
785
	usleep(200);
786
 
787
	return;
788
    }
789
}
790
 
791
/*
792
 *
793
 */
794
static void
795
RV620PLL1SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv,
796
		CARD8 ScalerDiv, CARD8 SymPostDiv, CARD32 Control)
797
{
798
    RHDFUNC(PLL);
799
 
800
    /* switch to external */
801
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0);
802
    RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, 0x00000200, 0x00000300);
803
    RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, 0, 0x00000100);
804
 
805
    RHDRegMask(PLL, P1PLL_CNTL, 0x00000001, 0x00000001); /* reset */
806
    usleep(2);
807
    RHDRegMask(PLL, P1PLL_CNTL, 0x00000002, 0x00000002); /* power down */
808
    usleep(10);
809
    RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000); /* reset anti-glitch */
810
 
811
    RHDRegWrite(PLL, EXT1_PPLL_CNTL, Control);
812
 
813
    RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, ScalerDiv, 0x0000003F);
814
 
815
    RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 1); /* lock */
816
 
817
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00000001);
818
 
819
    RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, RefDiv);
820
    RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, FBDiv);
821
    RHDRegMask(PLL, EXT1_PPLL_POST_DIV, PostDiv, 0x0000007F);
822
    RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, SymPostDiv, 0x0000007F);
823
 
824
    usleep(10);
825
    RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0); /* unlock */
826
 
827
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00000002); /* power up */
828
    usleep(10);
829
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000); /* undo reset anti-glitch */
830
 
831
    PLL1Calibrate(PLL);
832
 
833
    /* switch back to the pll */
834
    RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, 0, 0x00000300);
835
    RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, 0x00000100, 0x00000100);
836
    RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00000001);
837
 
838
    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x80000000); /* new and undocumented */
839
}
840
 
841
/*
842
 *
843
 */
844
static void
845
RV620PLL2SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv,
846
		CARD8 ScalerDiv, CARD8 SymPostDiv, CARD32 Control)
847
{
848
    RHDFUNC(PLL);
849
 
850
    /* switch to external */
851
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0);
852
    RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, 0x00000200, 0x00000300);
853
    RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, 0, 0x00000100);
854
 
855
    RHDRegMask(PLL, P2PLL_CNTL, 0x00000001, 0x00000001); /* reset */
856
    usleep(2);
857
    RHDRegMask(PLL, P2PLL_CNTL, 0x00000002, 0x00000002); /* power down */
858
    usleep(10);
859
    RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000); /* reset anti-glitch */
860
 
861
    RHDRegWrite(PLL, EXT2_PPLL_CNTL, Control);
862
 
863
    RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, ScalerDiv, 0x0000003F);
864
 
865
    RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 1); /* lock */
866
 
867
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00000001);
868
 
869
    RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, RefDiv);
870
    RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, FBDiv);
871
    RHDRegMask(PLL, EXT2_PPLL_POST_DIV, PostDiv, 0x0000007F);
872
    RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, SymPostDiv, 0x0000007F);
873
 
874
    usleep(10);
875
    RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0); /* unlock */
876
 
877
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00000002); /* power up */
878
    usleep(10);
879
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000); /* undo reset anti-glitch */
880
 
881
    PLL2Calibrate(PLL);
882
 
883
    /* switch back to the pll */
884
    RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, 0, 0x00000300);
885
    RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, 0x00000100, 0x00000100);
886
    RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00000001);
887
 
888
    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x80000000); /* new and undocumented */
889
}
890
 
891
/*
892
 *
893
 */
894
static void
895
RV620PLL1Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider,
896
	     CARD16 FeedbackDivider, CARD8 PostDivider)
897
{
898
    RHDPtr rhdPtr = RHDPTRI(PLL);
899
    Bool HasDccg = RV620DCCGCLKAvailable(PLL);
900
    CARD32 RefDiv, FBDiv, PostDiv, Control;
901
    CARD8 ScalerDiv, SymPostDiv;
902
 
903
    RHDFUNC(PLL);
904
 
905
    if (HasDccg)
906
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET);
907
 
908
    /* Disable Spread Spectrum */
909
    RHDRegMask(PLL, P1PLL_INT_SS_CNTL, 0, 0x00000001);
910
 
911
    RefDiv = ReferenceDivider;
912
 
913
    FBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & ~0x07FF003F;
914
    FBDiv |= ((FeedbackDivider << 16) | 0x0030) & 0x07FF003F;
915
 
916
    PostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & ~0x0000007F;
917
    PostDiv |= PostDivider & 0x0000007F;
918
 
919
    /* introduce flags for this, like on unichrome */
920
    ScalerDiv = 2; /* scaler post divider, 4 for UPDP */
921
 
922
    SymPostDiv = PostDivider & 0x0000007F;
923
 
924
    Control = PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider);
925
 
926
    RV620PLL1SetLow(PLL, RefDiv, FBDiv, PostDiv, ScalerDiv, SymPostDiv,
927
		    Control);
928
 
929
    if (rhdPtr->Crtc[0]->PLL == PLL)
930
	R500PLLCRTCGrab(PLL, FALSE);
931
    if (rhdPtr->Crtc[1]->PLL == PLL)
932
	R500PLLCRTCGrab(PLL, TRUE);
933
 
934
    if (HasDccg)
935
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB);
936
}
937
 
938
/*
939
 *
940
 */
941
static void
942
RV620PLL2Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider,
943
	     CARD16 FeedbackDivider, CARD8 PostDivider)
944
{
945
    RHDPtr rhdPtr = RHDPTRI(PLL);
946
    Bool HasDccg = RV620DCCGCLKAvailable(PLL);
947
    CARD32 RefDiv, FBDiv, PostDiv, Control;
948
    CARD8 ScalerDiv, SymPostDiv;
949
 
950
    RHDFUNC(PLL);
951
 
952
    if (HasDccg)
953
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET);
954
 
955
    /* Disable Spread Spectrum */
956
    RHDRegMask(PLL, P2PLL_INT_SS_CNTL, 0, 0x00000001);
957
 
958
    RefDiv = ReferenceDivider;
959
 
960
    FBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & ~0x07FF003F;
961
    FBDiv |= ((FeedbackDivider << 16) | 0x0030) & 0x07FF003F;
962
 
963
    PostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & ~0x0000007F;
964
    PostDiv |= PostDivider & 0x0000007F;
965
 
966
    /* introduce flags for this, like on unichrome */
967
    ScalerDiv = 2; /* scaler post divider, 4 for UPDP */
968
 
969
    SymPostDiv = PostDivider & 0x0000007F;
970
 
971
    Control = PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider);
972
 
973
    RV620PLL2SetLow(PLL, RefDiv, FBDiv, PostDiv, ScalerDiv, SymPostDiv,
974
		    Control);
975
 
976
    if (rhdPtr->Crtc[0]->PLL == PLL)
977
	R500PLLCRTCGrab(PLL, FALSE);
978
    if (rhdPtr->Crtc[1]->PLL == PLL)
979
	R500PLLCRTCGrab(PLL, TRUE);
980
 
981
    if (HasDccg)
982
	RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB);
983
}
984
 
985
/*
986
 *
987
 */
988
static void
989
RV620PLL1Save(struct rhdPLL *PLL)
990
{
991
    RHDFUNC(PLL);
992
 
993
    PLL->StoreActive = !(RHDRegRead(PLL, P1PLL_CNTL) & 0x03);
994
    PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV);
995
    PLL->StoreFBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV);
996
    PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV);
997
    PLL->StorePostDivSrc = RHDRegRead(PLL, EXT1_PPLL_POST_DIV_SRC);
998
    PLL->StoreControl = RHDRegRead(PLL, EXT1_PPLL_CNTL);
999
    PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL);
1000
 
1001
    PLL->StoreGlitchReset = RHDRegRead(PLL, P1PLL_CNTL) & 0x00002000;
1002
 
1003
    PLL->StoreScalerPostDiv = RHDRegRead(PLL, P1PLL_DISP_CLK_CNTL) & 0x003F;
1004
    PLL->StoreSymPostDiv = RHDRegRead(PLL, EXT1_SYM_PPLL_POST_DIV) & 0x007F;
1005
 
1006
    PLL->StoreCrtc1Owner = !(RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000);
1007
    PLL->StoreCrtc2Owner = !(RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000);
1008
 
1009
    PLL->StoreDCCGCLKOwner = RV620DCCGCLKAvailable(PLL);
1010
    if (PLL->StoreDCCGCLKOwner)
1011
	PLL->StoreDCCGCLK = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL);
1012
    else
1013
	PLL->StoreDCCGCLK = 0;
1014
 
1015
    PLL->Stored = TRUE;
1016
}
1017
 
1018
/*
1019
 *
1020
 */
1021
static void
1022
RV620PLL2Save(struct rhdPLL *PLL)
1023
{
1024
    RHDFUNC(PLL);
1025
 
1026
    PLL->StoreActive = !(RHDRegRead(PLL, P2PLL_CNTL) & 0x03);
1027
    PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV);
1028
    PLL->StoreFBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV);
1029
    PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV);
1030
    PLL->StorePostDivSrc = RHDRegRead(PLL, EXT2_PPLL_POST_DIV_SRC);
1031
    PLL->StoreControl = RHDRegRead(PLL, EXT2_PPLL_CNTL);
1032
    PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL);
1033
 
1034
    PLL->StoreGlitchReset = RHDRegRead(PLL, P2PLL_CNTL) & 0x00002000;
1035
 
1036
    PLL->StoreScalerPostDiv = RHDRegRead(PLL, P2PLL_DISP_CLK_CNTL) & 0x003F;
1037
    PLL->StoreSymPostDiv = RHDRegRead(PLL, EXT2_SYM_PPLL_POST_DIV) & 0x007F;
1038
 
1039
    PLL->StoreCrtc1Owner = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000;
1040
    PLL->StoreCrtc2Owner = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000;
1041
 
1042
    PLL->StoreDCCGCLKOwner = RV620DCCGCLKAvailable(PLL);
1043
    if (PLL->StoreDCCGCLKOwner)
1044
	PLL->StoreDCCGCLK = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL);
1045
    else
1046
	PLL->StoreDCCGCLK = 0;
1047
 
1048
    PLL->Stored = TRUE;
1049
}
1050
 
1051
/*
1052
 * Notice how we handle the DCCG ownership here. There is a difference between
1053
 * currently holding the DCCG and what was held when in the VT. With the
1054
 * solution here we no longer hardlock, but we do have the danger of keeping
1055
 * the DCCG in external mode for too long a time, if both PLL restores are
1056
 * too far apart. This is currently not an issue as VT restoration goes over
1057
 * the whole device in one go anyway; no partial restoration going on
1058
 */
1059
static void
1060
RV620PLL1Restore(struct rhdPLL *PLL)
1061
{
1062
    RHDFUNC(PLL);
1063
 
1064
    if (RV620DCCGCLKAvailable(PLL))
1065
	RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0x03, 0x00000003);
1066
 
1067
    if (PLL->StoreActive) {
1068
	RV620PLL1SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv,
1069
			PLL->StorePostDiv, PLL->StoreScalerPostDiv,
1070
			PLL->StoreSymPostDiv, PLL->StoreControl);
1071
	RHDRegMask(PLL, P1PLL_INT_SS_CNTL,
1072
		   PLL->StoreSpreadSpectrum, 0x00000001);
1073
 
1074
	if (PLL->StoreDCCGCLKOwner)
1075
	    RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK);
1076
 
1077
    } else {
1078
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
1079
 
1080
	/* lame attempt at at least restoring the old values */
1081
	RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, PLL->StoreRefDiv);
1082
	RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, PLL->StoreFBDiv);
1083
	RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PLL->StorePostDiv);
1084
	RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, PLL->StorePostDivSrc);
1085
	RHDRegWrite(PLL, EXT1_PPLL_CNTL, PLL->StoreControl);
1086
	RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, PLL->StoreScalerPostDiv, 0x003F);
1087
	RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, PLL->StoreSymPostDiv, 0x007F);
1088
	RHDRegWrite(PLL, P1PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum);
1089
 
1090
	if (PLL->StoreGlitchReset)
1091
	    RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000);
1092
	else
1093
	    RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000);
1094
    }
1095
 
1096
    if (PLL->StoreCrtc1Owner)
1097
	R500PLLCRTCGrab(PLL, FALSE);
1098
    if (PLL->StoreCrtc2Owner)
1099
	R500PLLCRTCGrab(PLL, TRUE);
1100
 
1101
    if (PLL->StoreDCCGCLKOwner)
1102
	RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK);
1103
}
1104
 
1105
/*
1106
 *
1107
 */
1108
static void
1109
RV620PLL2Restore(struct rhdPLL *PLL)
1110
{
1111
    RHDFUNC(PLL);
1112
 
1113
    if (RV620DCCGCLKAvailable(PLL))
1114
	RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0x03, 0x00000003);
1115
 
1116
    if (PLL->StoreActive) {
1117
	RV620PLL2SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv,
1118
			PLL->StorePostDiv, PLL->StoreScalerPostDiv,
1119
			PLL->StoreSymPostDiv, PLL->StoreControl);
1120
	RHDRegMask(PLL, P2PLL_INT_SS_CNTL,
1121
		   PLL->StoreSpreadSpectrum, 0x00000001);
1122
    } else {
1123
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
1124
 
1125
	/* lame attempt at at least restoring the old values */
1126
	RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, PLL->StoreRefDiv);
1127
	RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, PLL->StoreFBDiv);
1128
	RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PLL->StorePostDiv);
1129
	RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, PLL->StorePostDivSrc);
1130
	RHDRegWrite(PLL, EXT2_PPLL_CNTL, PLL->StoreControl);
1131
	RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, PLL->StoreScalerPostDiv, 0x003F);
1132
	RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, PLL->StoreSymPostDiv, 0x007F);
1133
	RHDRegWrite(PLL, P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum);
1134
 
1135
	if (PLL->StoreGlitchReset)
1136
	    RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000);
1137
	else
1138
	    RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000);
1139
    }
1140
 
1141
    if (PLL->StoreCrtc1Owner)
1142
	R500PLLCRTCGrab(PLL, FALSE);
1143
    if (PLL->StoreCrtc2Owner)
1144
	R500PLLCRTCGrab(PLL, TRUE);
1145
 
1146
    if (PLL->StoreDCCGCLKOwner)
1147
	RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK);
1148
}
1149
 
1150
/* Some defaults for when we don't have this info */
1151
/* XTAL is visible on the cards */
1152
#define RHD_PLL_REFERENCE_DEFAULT            27000
1153
/* these required quite some testing */
1154
#define RHD_R500_PLL_INTERNAL_MIN_DEFAULT   648000
1155
#define RHD_RV620_PLL_INTERNAL_MIN_DEFAULT  702000
1156
/* Lowest value seen so far */
1157
#define RHD_PLL_INTERNAL_MAX_DEFAULT       1100000
1158
#define RHD_PLL_MIN_DEFAULT                  16000 /* guess */
1159
#define RHD_PLL_MAX_DEFAULT                 400000 /* 400Mhz modes... hrm */
1160
 
1161
enum pllComp {
1162
    PLL_NONE,
1163
    PLL_MIN,
1164
    PLL_MAX
1165
};
1166
 
1167
/*
1168
 *
1169
 */
1170
#ifdef ATOM_BIOS
1171
static Bool
1172
getPLLValuesFromAtomBIOS(RHDPtr rhdPtr,
1173
			 AtomBiosRequestID func, char *msg, CARD32 *val, enum pllComp comp)
1174
{
1175
    AtomBiosArgRec arg;
1176
    AtomBiosResult ret;
1177
 
1178
    if (rhdPtr->atomBIOS) {
1179
	ret = RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
1180
			      func, &arg);
1181
	if (ret == ATOM_SUCCESS) {
1182
	    if (arg.val) {
1183
		switch (comp) {
1184
		    case PLL_MAX:
1185
			if (arg.val < *val)
1186
			    xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING,
1187
				       "Lower %s detected than the default: %lu %lu.\n"
1188
				       "Please contact the authors ASAP.\n", msg,
1189
				       (unsigned long)*val, (unsigned long)arg.val * 10);
1190
			break;
1191
		    case PLL_MIN:
1192
			if (arg.val > *val)
1193
			    xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING,
1194
				       "Higher %s detected than the default: %lu %lu.\n"
1195
				       "Please contact the authors ASAP.\n", msg,
1196
				       (unsigned long)*val, (unsigned long)arg.val * 10);
1197
			break;
1198
		    default:
1199
			break;
1200
		}
1201
		*val = arg.val;
1202
	    }
1203
	}
1204
	return TRUE;
1205
    } else
1206
	xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Failed to retrieve the %s"
1207
		   " clock from ATOM.\n",msg);
1208
    return FALSE;
1209
}
1210
#endif
1211
 
1212
/*
1213
 *
1214
 */
1215
void
1216
RHDSetupLimits(RHDPtr rhdPtr, CARD32 *RefClock,
1217
	       CARD32 *IntMin, CARD32 *IntMax,
1218
	       CARD32 *PixMin, CARD32 *PixMax)
1219
{
1220
    /* Retrieve the internal PLL frequency limits*/
1221
    *RefClock = RHD_PLL_REFERENCE_DEFAULT;
1222
    if (rhdPtr->ChipSet < RHD_RV620)
1223
	*IntMin = RHD_R500_PLL_INTERNAL_MIN_DEFAULT;
1224
    else
1225
	*IntMin = RHD_RV620_PLL_INTERNAL_MIN_DEFAULT;
1226
 
1227
    *IntMax = RHD_PLL_INTERNAL_MAX_DEFAULT;
1228
 
1229
    /* keep the defaults */
1230
    *PixMin = RHD_PLL_MIN_DEFAULT;
1231
    *PixMax = RHD_PLL_MAX_DEFAULT;
1232
 
1233
#ifdef ATOM_BIOS
1234
    getPLLValuesFromAtomBIOS(rhdPtr, GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, "minimum PLL output",
1235
			     IntMin,  PLL_MIN);
1236
    getPLLValuesFromAtomBIOS(rhdPtr, GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, "maximum PLL output",
1237
			     IntMax, PLL_MAX);
1238
    getPLLValuesFromAtomBIOS(rhdPtr, GET_MAX_PIXEL_CLK, "Pixel Clock",
1239
			     PixMax, PLL_MAX);
1240
    getPLLValuesFromAtomBIOS(rhdPtr, GET_REF_CLOCK, "reference clock",
1241
			     RefClock, PLL_NONE);
1242
    if (*IntMax == 0) {
1243
	if (rhdPtr->ChipSet < RHD_RV620)
1244
	    *IntMax = RHD_R500_PLL_INTERNAL_MIN_DEFAULT;
1245
	else
1246
	    *IntMax = RHD_RV620_PLL_INTERNAL_MIN_DEFAULT;
1247
 
1248
	xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "AtomBIOS reports maximum VCO freq 0. "
1249
		   "Using %lu instead\n",(unsigned long)*IntMax);
1250
    }
1251
#endif
1252
}
1253
 
1254
/*
1255
 *
1256
 */
1257
Bool
1258
RHDPLLsInit(RHDPtr rhdPtr)
1259
{
1260
    struct rhdPLL *PLL;
1261
    CARD32 RefClock, IntMin, IntMax, PixMin, PixMax;
1262
 
1263
    RHDFUNC(rhdPtr);
1264
 
1265
    if (RHDUseAtom(rhdPtr, NULL, atomUsagePLL))
1266
	return FALSE;
1267
 
1268
    RHDSetupLimits(rhdPtr, &RefClock, &IntMin, &IntMax, &PixMin, &PixMax);
1269
 
1270
    /* PLL1 */
1271
    PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1);
1272
 
1273
    PLL->scrnIndex = rhdPtr->scrnIndex;
1274
    PLL->Name = PLL_NAME_PLL1;
1275
    PLL->Id = PLL_ID_PLL1;
1276
 
1277
    PLL->RefClock = RefClock;
1278
    PLL->IntMin = IntMin;
1279
    PLL->IntMax = IntMax;
1280
    PLL->PixMin = PixMin;
1281
    PLL->PixMax = PixMax;
1282
 
1283
    PLL->Valid = NULL;
1284
    if (rhdPtr->ChipSet < RHD_RV620) {
1285
	PLL->Set = R500PLL1Set;
1286
	PLL->Power = R500PLL1Power;
1287
	PLL->Save = R500PLL1Save;
1288
	PLL->Restore = R500PLL1Restore;
1289
    } else {
1290
	PLL->Set = RV620PLL1Set;
1291
	PLL->Power = RV620PLL1Power;
1292
	PLL->Save = RV620PLL1Save;
1293
	PLL->Restore = RV620PLL1Restore;
1294
    }
1295
 
1296
    rhdPtr->PLLs[0] = PLL;
1297
 
1298
    /* PLL2 */
1299
    PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1);
1300
 
1301
    PLL->scrnIndex = rhdPtr->scrnIndex;
1302
    PLL->Name = PLL_NAME_PLL2;
1303
    PLL->Id = PLL_ID_PLL2;
1304
 
1305
    PLL->RefClock = RefClock;
1306
    PLL->IntMin = IntMin;
1307
    PLL->IntMax = IntMax;
1308
    PLL->PixMin = PixMin;
1309
    PLL->PixMax = PixMax;
1310
 
1311
    PLL->Valid = NULL;
1312
    if (rhdPtr->ChipSet < RHD_RV620) {
1313
	PLL->Set = R500PLL2Set;
1314
	PLL->Power = R500PLL2Power;
1315
	PLL->Save = R500PLL2Save;
1316
	PLL->Restore = R500PLL2Restore;
1317
    } else {
1318
	PLL->Set = RV620PLL2Set;
1319
	PLL->Power = RV620PLL2Power;
1320
	PLL->Save = RV620PLL2Save;
1321
	PLL->Restore = RV620PLL2Restore;
1322
    }
1323
 
1324
    rhdPtr->PLLs[1] = PLL;
1325
 
1326
    return TRUE;
1327
}
1328
 
1329
/*
1330
 *
1331
 */
1332
ModeStatus
1333
RHDPLLValid(struct rhdPLL *PLL, CARD32 Clock)
1334
{
1335
    RHDFUNC(PLL);
1336
 
1337
    if (Clock < PLL->PixMin)
1338
	return MODE_CLOCK_LOW;
1339
    if (Clock > PLL->PixMax)
1340
	return MODE_CLOCK_HIGH;
1341
 
1342
    if (PLL->Valid)
1343
	return PLL->Valid(PLL, Clock);
1344
    else
1345
	return MODE_OK;
1346
}
1347
 
1348
 
1349
/*
1350
 * Calculate the PLL parameters for a given dotclock.
1351
 *
1352
 * This calculation uses a linear approximation of an experimentally found
1353
 * curve that delimits reference versus feedback dividers on rv610. This curve
1354
 * can be shifted towards higher feedback divider through increasing the gain
1355
 * control, but the effect of this is rather limited.
1356
 *
1357
 * Since this upper limit still provides a wide enough range with enough
1358
 * granularity, we use it for all r5xx and r6xx devices.
1359
 */
1360
static Bool
1361
PLLCalculate(struct rhdPLL *PLL, CARD32 PixelClock,
1362
	     CARD16 *RefDivider, CARD16 *FBDivider, CARD8 *PostDivider)
1363
{
1364
/* limited by the number of bits available */
1365
#define FB_DIV_LIMIT 2048
1366
#define REF_DIV_LIMIT 1024
1367
#define POST_DIV_LIMIT 128
1368
 
1369
    CARD32 FBDiv, RefDiv, PostDiv, BestDiff = 0xFFFFFFFF;
1370
    float Ratio;
1371
 
1372
    Ratio = ((float) PixelClock) / ((float) PLL->RefClock);
1373
 
1374
    for (PostDiv = 2; PostDiv < POST_DIV_LIMIT; PostDiv++) {
1375
	CARD32 VCOOut = PixelClock * PostDiv;
1376
 
1377
	/* we are conservative and avoid the limits */
1378
	if (VCOOut <= PLL->IntMin)
1379
	    continue;
1380
	if (VCOOut >= PLL->IntMax)
1381
	    break;
1382
 
1383
        for (RefDiv = 1; RefDiv <= REF_DIV_LIMIT; RefDiv++) {
1384
	    CARD32 Diff;
1385
 
1386
	    FBDiv = (CARD32) ((Ratio * PostDiv * RefDiv) + 0.5);
1387
 
1388
	    if (FBDiv >= FB_DIV_LIMIT)
1389
		break;
1390
	    if (FBDiv > (500 + (13 * RefDiv))) /* rv6x0 limit */
1391
		break;
1392
 
1393
	    Diff = abs( PixelClock - (FBDiv * PLL->RefClock) / (PostDiv * RefDiv) );
1394
 
1395
	    if (Diff < BestDiff) {
1396
		*FBDivider = FBDiv;
1397
		*RefDivider = RefDiv;
1398
		*PostDivider = PostDiv;
1399
		BestDiff = Diff;
1400
	    }
1401
 
1402
	    if (BestDiff == 0)
1403
		break;
1404
	}
1405
	if (BestDiff == 0)
1406
	    break;
1407
    }
1408
 
1409
    if (BestDiff != 0xFFFFFFFF) {
1410
	RHDDebug(PLL->scrnIndex, "PLL Calculation: %dkHz = "
1411
		   "(((%i / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n",
1412
		   (int) PixelClock, (unsigned int) PLL->RefClock, *RefDivider,
1413
		   *FBDivider, *PostDivider, (int) BestDiff);
1414
	return TRUE;
1415
    } else { /* Should never happen */
1416
	xf86DrvMsg(PLL->scrnIndex, X_ERROR,
1417
		   "%s: Failed to get a valid PLL setting for %dkHz\n",
1418
		   __func__, (int) PixelClock);
1419
	return FALSE;
1420
    }
1421
}
1422
 
1423
/*
1424
 *
1425
 */
1426
void
1427
RHDPLLSet(struct rhdPLL *PLL, CARD32 Clock)
1428
{
1429
    CARD16 RefDivider = 0, FBDivider = 0;
1430
    CARD8 PostDivider = 0;
1431
 
1432
    RHDDebug(PLL->scrnIndex, "%s: Setting %s to %dkHz\n", __func__,
1433
	     PLL->Name, Clock);
1434
 
1435
    if (PLLCalculate(PLL, Clock, &RefDivider, &FBDivider, &PostDivider)) {
1436
	PLL->Set(PLL, Clock, RefDivider, FBDivider, PostDivider);
1437
 
1438
	PLL->CurrentClock = Clock;
1439
	PLL->Active = TRUE;
1440
    } else
1441
	xf86DrvMsg(PLL->scrnIndex, X_WARNING,
1442
		   "%s: Not altering any settings.\n", __func__);
1443
}
1444
 
1445
/*
1446
 *
1447
 */
1448
void
1449
RHDPLLPower(struct rhdPLL *PLL, int Power)
1450
{
1451
    RHDFUNC(PLL);
1452
 
1453
    if (PLL->Power)
1454
	PLL->Power(PLL, Power);
1455
}
1456
 
1457
/*
1458
 *
1459
 */
1460
void
1461
RHDPLLsPowerAll(RHDPtr rhdPtr, int Power)
1462
{
1463
    struct rhdPLL *PLL;
1464
 
1465
    RHDFUNC(rhdPtr);
1466
 
1467
    PLL = rhdPtr->PLLs[0];
1468
    if (PLL->Power)
1469
	PLL->Power(PLL, Power);
1470
 
1471
    PLL = rhdPtr->PLLs[1];
1472
    if (PLL->Power)
1473
	PLL->Power(PLL, Power);
1474
}
1475
 
1476
/*
1477
 *
1478
 */
1479
void
1480
RHDPLLsShutdownInactive(RHDPtr rhdPtr)
1481
{
1482
    struct rhdPLL *PLL;
1483
 
1484
    RHDFUNC(rhdPtr);
1485
 
1486
    PLL = rhdPtr->PLLs[0];
1487
    if (PLL->Power && !PLL->Active)
1488
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
1489
 
1490
    PLL = rhdPtr->PLLs[1];
1491
    if (PLL->Power && !PLL->Active)
1492
	PLL->Power(PLL, RHD_POWER_SHUTDOWN);
1493
}
1494
 
1495
/*
1496
 *
1497
 */
1498
void
1499
RHDPLLsSave(RHDPtr rhdPtr)
1500
{
1501
    struct rhdPLL *PLL;
1502
 
1503
    RHDFUNC(rhdPtr);
1504
 
1505
    PLL = rhdPtr->PLLs[0];
1506
    if (PLL->Save)
1507
	PLL->Save(PLL);
1508
 
1509
    PLL = rhdPtr->PLLs[1];
1510
    if (PLL->Save)
1511
	PLL->Save(PLL);
1512
}
1513
 
1514
/*
1515
 *
1516
 */
1517
void
1518
RHDPLLsRestore(RHDPtr rhdPtr)
1519
{
1520
    struct rhdPLL *PLL;
1521
 
1522
    RHDFUNC(rhdPtr);
1523
 
1524
    PLL = rhdPtr->PLLs[0];
1525
    if (PLL->Restore)
1526
	PLL->Restore(PLL);
1527
 
1528
    PLL = rhdPtr->PLLs[1];
1529
    if (PLL->Restore)
1530
	PLL->Restore(PLL);
1531
}
1532
 
1533
/*
1534
 *
1535
 */
1536
void
1537
RHDPLLsDestroy(RHDPtr rhdPtr)
1538
{
1539
    RHDFUNC(rhdPtr);
1540
 
1541
    if (rhdPtr->PLLs[0] && rhdPtr->PLLs[0]->Private)
1542
	xfree(rhdPtr->PLLs[0]->Private);
1543
    xfree(rhdPtr->PLLs[0]);
1544
    if (rhdPtr->PLLs[1] && rhdPtr->PLLs[1]->Private)
1545
	xfree(rhdPtr->PLLs[1]->Private);
1546
    xfree(rhdPtr->PLLs[1]);
1547
}