Subversion Repositories Kolibri OS

Rev

Rev 1029 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1029 serge 1
/*
2
 * Copyright 2007, 2008  Luc Verhaegen 
3
 * Copyright 2007, 2008  Matthias Hopf 
4
 * Copyright 2007, 2008  Egbert Eich   
5
 * Copyright 2007, 2008  Advanced Micro Devices, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
#ifdef HAVE_CONFIG_H
27
#include "config.h"
28
#endif
29
 
30
#include "xf86.h"
31
 
32
/* for usleep */
33
#if HAVE_XF86_ANSIC_H
34
# include "xf86_ansic.h"
35
#else
36
# include 
37
#endif
38
 
39
#include "rhd.h"
40
#include "rhd_crtc.h"
41
#include "rhd_pll.h"
42
#include "rhd_lut.h"
43
#include "rhd_regs.h"
44
#include "rhd_modes.h"
45
#include "rhd_mc.h"
46
#ifdef ATOM_BIOS
47
# include "rhd_atombios.h"
48
#endif
49
 
50
#define D1_REG_OFFSET 0x0000
51
#define D2_REG_OFFSET 0x0800
52
#define FMT1_REG_OFFSET 0x0000
53
#define FMT2_REG_OFFSET 0x800
54
 
55
struct rhdCrtcFMTPrivate {
56
    CARD32 StoreControl;
57
    CARD32 StoreBitDepthControl;
58
    CARD32 StoreClampCntl;
59
};
60
 
61
struct rhdCrtcFBPrivate {
62
    CARD32 StoreGrphEnable;
63
    CARD32 StoreGrphControl;
64
    CARD32 StoreGrphXStart;
65
    CARD32 StoreGrphYStart;
66
    CARD32 StoreGrphXEnd;
67
    CARD32 StoreGrphYEnd;
68
    CARD32 StoreGrphSwap;
69
    CARD32 StoreGrphPrimarySurfaceAddress;
70
    CARD32 StoreGrphSurfaceOffsetX;
71
    CARD32 StoreGrphSurfaceOffsetY;
72
    CARD32 StoreGrphPitch;
73
    CARD32 StoreModeDesktopHeight;
74
};
75
 
76
struct rhdCrtcLUTPrivate {
77
    CARD32 StoreGrphLutSel;
78
};
79
 
80
struct rhdCrtcScalePrivate {
81
    CARD32 StoreModeViewPortSize;
82
 
83
    CARD32 StoreModeOverScanH;
84
    CARD32 StoreModeOverScanV;
85
 
86
    CARD32 StoreModeViewPortStart;
87
    CARD32 StoreScaleEnable;
88
    CARD32 StoreScaleTapControl;
89
    CARD32 StoreModeCenter;
90
    CARD32 StoreScaleHV;
91
    CARD32 StoreScaleHFilter;
92
    CARD32 StoreScaleVFilter;
93
    CARD32 StoreScaleDither;
94
};
95
 
96
struct rhdCrtcModePrivate {
97
    CARD32 StoreCrtcControl;
98
 
99
    CARD32 StoreCrtcHTotal;
100
    CARD32 StoreCrtcHBlankStartEnd;
101
    CARD32 StoreCrtcHSyncA;
102
    CARD32 StoreCrtcHSyncACntl;
103
    CARD32 StoreCrtcHSyncB;
104
    CARD32 StoreCrtcHSyncBCntl;
105
 
106
    CARD32 StoreCrtcVTotal;
107
    CARD32 StoreCrtcVBlankStartEnd;
108
    CARD32 StoreCrtcVSyncA;
109
    CARD32 StoreCrtcVSyncACntl;
110
    CARD32 StoreCrtcVSyncB;
111
    CARD32 StoreCrtcVSyncBCntl;
112
    CARD32 StoreCrtcCountControl;
113
 
114
    CARD32 StoreModeDataFormat;
115
    CARD32 StoreCrtcInterlaceControl;
116
 
117
    CARD32 StoreCrtcBlackColor;
118
    CARD32 StoreCrtcBlankControl;
119
};
120
 
121
/*
122
 * Checks whether Width, Height are within boundaries.
123
 * If MODE_OK is returned and pPitch is not NULL, it is set.
124
 */
125
static ModeStatus
126
DxFBValid(struct rhdCrtc *Crtc, CARD16 Width, CARD16 Height, int bpp,
127
	  CARD32 Offset, CARD32 Size, CARD32 *pPitch)
128
{
129
    RHDPtr rhdPtr = RHDPTRI(Crtc);
130
    ScrnInfoPtr pScrn = rhdPtr->pScrn;
131
 
132
    CARD16 Pitch;
133
    unsigned int BytesPerPixel;
134
    CARD8 PitchMask = 0xFF;
135
 
136
    RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name);
137
 
138
    /* If we hit this, then the memory claimed so far is not properly aligned */
139
    if (Offset & 0xFFF) {
140
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Offset (0x%08X) is invalid!\n",
141
		   __func__, (int) Offset);
142
      return MODE_ERROR;
143
    }
144
 
145
    switch (pScrn->bitsPerPixel) {
146
      case 8:
147
        BytesPerPixel = 1;
148
        break;
149
      case 15:
150
      case 16:
151
        BytesPerPixel = 2;
152
        PitchMask /= BytesPerPixel;
153
        break;
154
     case 24:
155
     case 32:
156
       BytesPerPixel = 4;
157
       PitchMask /= BytesPerPixel;
158
       break;
159
     default:
160
	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: %dbpp is not implemented!\n",
161
		   __func__, pScrn->bitsPerPixel);
162
       return MODE_BAD;
163
    }
164
 
165
    if((Width==720)&&(Height==400))    //skip textmode
166
      return MODE_BAD;
167
 
168
     /* Be reasonable */
169
    if (Width < 640)
170
      return MODE_H_ILLEGAL;
171
    if (Height < 480)
172
      return MODE_V_ILLEGAL;
173
 
174
    /* D1GRPH_X_START is 14bits while D1_MODE_VIEWPORT_X_START is only 13 bits.
175
     * Since it is reasonable to assume that modes will be at least 1x1
176
     * limit at 13bits + 1 */
177
    if (Width > 0x2000)
178
      return MODE_VIRTUAL_X;
179
 
180
    /* D1GRPH_Y_START is 14bits while D1_MODE_VIEWPORT_Y_START is only 13 bits.
181
     * Since it is reasonable to assume that modes will be at least 1x1
182
     * limit at 13bits + 1 */
183
    if (Height > 0x2000)
184
      return MODE_VIRTUAL_Y;
185
 
186
    Pitch = (Width + PitchMask) & ~PitchMask;
187
    /* D1_PITCH limit: should never happen after clamping Width to 0x2000 */
188
    if (Pitch >= 0x4000)
189
      return MODE_VIRTUAL_X;
190
 
191
    if ((Pitch * BytesPerPixel * Height) > Size)
192
      return MODE_MEM_VIRT;
193
 
194
    if (pPitch)
195
      *pPitch = Pitch;
196
    return MODE_OK;
197
}
198
 
199
/*
200
 *
201
 */
202
static void
203
DxFBSet(struct rhdCrtc *Crtc, CARD16 Pitch, CARD16 Width, CARD16 Height,
204
	int bpp, CARD32 Offset)
205
{
206
    RHDPtr rhdPtr = RHDPTRI(Crtc);
207
    CARD16 RegOff;
208
 
209
    RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s (%i[%i]x%i@%ibpp)  +0x%x )\n",
210
	     __func__, Crtc->Name, Width, Pitch, Height, bpp, Offset);
211
 
212
    if (Crtc->Id == RHD_CRTC_1)
213
      RegOff = D1_REG_OFFSET;
214
    else
215
      RegOff = D2_REG_OFFSET;
216
 
217
    RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 1, 0x00000001);
218
 
219
    /* disable R/B swap, disable tiling, disable 16bit alpha, etc. */
220
    RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, 0);
221
 
222
    switch (bpp) {
223
      case 8:
224
        RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0, 0x00000703);
225
        break;
226
      case 15:
227
        RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000001, 0x00000703);
228
        break;
229
      case 16:
230
        RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000101, 0x00000703);
231
        break;
232
      case 24:
233
      case 32:
234
        default:
235
        RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000002, 0x00000703);
236
        break;
237
    /* TODO: 64bpp ;p */
238
    }
239
 
240
    /* Make sure that we are not swapping colours around */
241
    if (rhdPtr->ChipSet > RHD_R600)
242
      RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, 0);
243
    /* R5xx - RS690 case is GRPH_CONTROL bit 16 */
244
 
245
    RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS,
246
                rhdPtr->FbIntAddress + Offset);
247
    RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, Pitch);
248
    RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X, 0);
249
    RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y, 0);
250
    RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, 0);
251
    RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, 0);
252
    RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, Width);
253
    RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, Height);
254
 
255
    /* D1Mode registers */
256
    RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, Height);
257
 
258
    Crtc->Pitch = Pitch;
259
    Crtc->Width = Width;
260
    Crtc->Height = Height;
261
    Crtc->bpp = bpp;
262
    Crtc->Offset = Offset;
263
}
264
 
265
/*
266
 *
267
 */
268
static void
269
DxFBSave(struct rhdCrtc *Crtc)
270
{
271
    struct rhdCrtcFBPrivate *FBPriv;
272
    CARD32 RegOff;
273
 
274
    if (!Crtc->FBPriv)
275
	FBPriv = xnfcalloc(1, sizeof(struct rhdCrtcFBPrivate));
276
    else
277
	FBPriv = Crtc->FBPriv;
278
 
279
    if (Crtc->Id == RHD_CRTC_1)
280
	RegOff = D1_REG_OFFSET;
281
    else
282
	RegOff = D2_REG_OFFSET;
283
 
284
    FBPriv->StoreGrphEnable = RHDRegRead(Crtc, RegOff + D1GRPH_ENABLE);
285
    FBPriv->StoreGrphControl = RHDRegRead(Crtc, RegOff + D1GRPH_CONTROL);
286
    FBPriv->StoreGrphXStart = RHDRegRead(Crtc, RegOff + D1GRPH_X_START);
287
    FBPriv->StoreGrphYStart = RHDRegRead(Crtc, RegOff + D1GRPH_Y_START);
288
    FBPriv->StoreGrphXEnd = RHDRegRead(Crtc, RegOff + D1GRPH_X_END);
289
    FBPriv->StoreGrphYEnd = RHDRegRead(Crtc, RegOff + D1GRPH_Y_END);
290
    if (RHDPTRI(Crtc)->ChipSet >= RHD_R600)
291
	FBPriv->StoreGrphSwap = RHDRegRead(Crtc, RegOff + D1GRPH_SWAP_CNTL);
292
    FBPriv->StoreGrphPrimarySurfaceAddress =
293
	RHDRegRead(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS);
294
    FBPriv->StoreGrphSurfaceOffsetX =
295
	RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X);
296
    FBPriv->StoreGrphSurfaceOffsetY =
297
	RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y);
298
    FBPriv->StoreGrphPitch = RHDRegRead(Crtc, RegOff + D1GRPH_PITCH);
299
    FBPriv->StoreModeDesktopHeight = RHDRegRead(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT);
300
 
301
    Crtc->FBPriv = FBPriv;
302
}
303
 
304
/*
305
 *
306
 */
307
static void
308
DxFBRestore(struct rhdCrtc *Crtc)
309
{
310
    struct rhdCrtcFBPrivate *FBPriv = Crtc->FBPriv;
311
    CARD32 RegOff;
312
 
313
    if (!FBPriv) {
314
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
315
		   __func__);
316
	return;
317
    }
318
 
319
    if (Crtc->Id == RHD_CRTC_1)
320
	RegOff = D1_REG_OFFSET;
321
    else
322
	RegOff = D2_REG_OFFSET;
323
 
324
    /* FBSet */
325
    RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, FBPriv->StoreGrphControl);
326
    RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, FBPriv->StoreGrphXStart);
327
    RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, FBPriv->StoreGrphYStart);
328
    RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, FBPriv->StoreGrphXEnd);
329
    RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, FBPriv->StoreGrphYEnd);
330
    if (RHDPTRI(Crtc)->ChipSet >= RHD_R600)
331
	RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, FBPriv->StoreGrphSwap);
332
 
333
    /* disable read requests */
334
    RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0x01000000, 0x01000000);
335
    RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 0, 0x00000001);
336
    usleep (10);
337
 
338
    RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS,
339
		FBPriv->StoreGrphPrimarySurfaceAddress);
340
    usleep(10);
341
 
342
    RHDRegWrite(Crtc, RegOff + D1GRPH_ENABLE, FBPriv->StoreGrphEnable);
343
 
344
    RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X,
345
		FBPriv->StoreGrphSurfaceOffsetX);
346
    RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y,
347
		FBPriv->StoreGrphSurfaceOffsetY);
348
 
349
    RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, FBPriv->StoreGrphPitch);
350
    RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, FBPriv->StoreModeDesktopHeight);
351
}
352
 
353
/*
354
 *
355
 */
356
static void
357
DxFBDestroy(struct rhdCrtc *Crtc)
358
{
359
    if (Crtc->FBPriv)
360
	xfree(Crtc->FBPriv);
361
    Crtc->FBPriv = NULL;
362
}
363
 
364
/*
365
 *
366
 */
367
static ModeStatus
368
DxModeValid(struct rhdCrtc *Crtc, DisplayModePtr Mode)
369
{
370
  CARD32 tmp;
371
 
372
    RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
373
 
374
    /* Work around HW bug: need at least 2 lines of front porch
375
       for interlaced mode */
376
    if ((Mode->Flags & V_INTERLACE)
377
	&& (Mode->CrtcVSyncStart < (Mode->CrtcVDisplay + 2))) {
378
	Mode->CrtcVSyncStart = Mode->CrtcVDisplay + 2;
379
	Mode->CrtcVAdjusted = TRUE;
380
    }
381
 
382
    /* D1CRTC_H_TOTAL - 1 : 13bits */
383
  if (Mode->CrtcHTotal > 0x2000)
384
    return MODE_BAD_HVALUE;
385
 
386
  tmp = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart;
387
    /* D1CRTC_H_BLANK_START: 13bits */
388
  if (tmp >= 0x2000)
389
    return MODE_BAD_HVALUE;
390
 
391
  tmp = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart;
392
    /* D1CRTC_H_BLANK_END: 13bits */
393
  if (tmp >= 0x2000)
394
    return MODE_BAD_HVALUE;
395
 
396
  tmp = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart;
397
    /* D1CRTC_H_SYNC_A_END: 13bits */
398
  if (tmp >= 0x2000)
399
    return MODE_HSYNC_WIDE;
400
 
401
    /* D1CRTC_V_TOTAL - 1 : 13bits */
402
  if (Mode->CrtcVTotal > 0x2000)
403
    return MODE_BAD_VVALUE;
404
 
405
  tmp = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart;
406
    /* D1CRTC_V_BLANK_START: 13bits */
407
  if (tmp >= 0x2000)
408
    return MODE_BAD_VVALUE;
409
 
410
  tmp = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart;
411
    /* D1CRTC_V_BLANK_END: 13bits */
412
  if (tmp >= 0x2000)
413
    return MODE_BAD_VVALUE;
414
 
415
  tmp = Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart;
416
    /* D1CRTC_V_SYNC_A_END: 13bits */
417
  if (tmp >= 0x2000)
418
    return MODE_VSYNC_WIDE;
419
 
420
  return MODE_OK;
421
}
422
 
423
/*
424
 *
425
 */
426
static void
427
DxModeSet(struct rhdCrtc *Crtc, DisplayModePtr Mode)
428
{
429
    RHDPtr rhdPtr = RHDPTRI(Crtc);
430
  CARD16 BlankStart, BlankEnd;
431
  CARD16 RegOff;
432
 
433
    RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name);
434
 
435
    if (rhdPtr->verbosity > 6) {
436
	xf86DrvMsg(Crtc->scrnIndex, X_INFO, "%s: Setting ",__func__);
437
	RHDPrintModeline(Mode);
438
    }
439
 
440
  if (Crtc->Id == RHD_CRTC_1)
441
    RegOff = D1_REG_OFFSET;
442
  else
443
    RegOff = D2_REG_OFFSET;
444
 
445
    /* enable read requests */
446
  RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0, 0x01000000);
447
 
448
    /* Horizontal */
449
  RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, Mode->CrtcHTotal - 1);
450
 
451
  BlankStart = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart;
452
  BlankEnd = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart;
453
  RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END,
454
  BlankStart | (BlankEnd << 16));
455
 
456
  RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A,
457
             (Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) << 16);
458
  RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC);
459
 
460
    /* Vertical */
461
  RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, Mode->CrtcVTotal - 1);
462
 
463
  BlankStart = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart;
464
  BlankEnd = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart;
465
  RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END,
466
              BlankStart | (BlankEnd << 16));
467
 
468
    /* set interlaced */
469
    if (Mode->Flags & V_INTERLACE) {
470
	RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x1);
471
	RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x1);
472
    } else {
473
	RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x0);
474
	RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x0);
475
    }
476
 
477
  RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A,
478
             (Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart) << 16);
479
  RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC);
480
 
481
    /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes */
482
    RHDRegMask(Crtc, RegOff + D1CRTC_COUNT_CONTROL, 0x0, 0x1);
483
 
484
  Crtc->CurrentMode = Mode;
485
}
486
 
487
/*
488
 *
489
 */
490
static void
491
DxModeSave(struct rhdCrtc *Crtc)
492
{
493
    struct rhdCrtcModePrivate *ModePriv;
494
    CARD32 RegOff;
495
 
496
    if (!Crtc->ModePriv)
497
	ModePriv = xnfcalloc(1, sizeof(struct rhdCrtcModePrivate));
498
    else
499
	ModePriv = Crtc->ModePriv;
500
 
501
    if (Crtc->Id == RHD_CRTC_1)
502
	RegOff = D1_REG_OFFSET;
503
    else
504
	RegOff = D2_REG_OFFSET;
505
 
506
    ModePriv->StoreCrtcControl = RHDRegRead(Crtc, RegOff + D1CRTC_CONTROL);
507
 
508
    ModePriv->StoreCrtcHTotal = RHDRegRead(Crtc, RegOff + D1CRTC_H_TOTAL);
509
    ModePriv->StoreCrtcHBlankStartEnd =
510
	RHDRegRead(Crtc, RegOff + D1CRTC_H_BLANK_START_END);
511
    ModePriv->StoreCrtcHSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A);
512
    ModePriv->StoreCrtcHSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL);
513
    ModePriv->StoreCrtcHSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B);
514
    ModePriv->StoreCrtcHSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL);
515
 
516
    ModePriv->StoreModeDataFormat = RHDRegRead(Crtc, RegOff + D1MODE_DATA_FORMAT);
517
    ModePriv->StoreCrtcInterlaceControl = RHDRegRead(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL);
518
 
519
    ModePriv->StoreCrtcVTotal = RHDRegRead(Crtc, RegOff + D1CRTC_V_TOTAL);
520
    ModePriv->StoreCrtcVBlankStartEnd =
521
	RHDRegRead(Crtc, RegOff + D1CRTC_V_BLANK_START_END);
522
    ModePriv->StoreCrtcVSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A);
523
    ModePriv->StoreCrtcVSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL);
524
    ModePriv->StoreCrtcVSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B);
525
    ModePriv->StoreCrtcVSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL);
526
 
527
    ModePriv->StoreCrtcBlackColor = RHDRegRead(Crtc, RegOff + D1CRTC_BLACK_COLOR);
528
    ModePriv->StoreCrtcBlankControl = RHDRegRead(Crtc, RegOff + D1CRTC_BLANK_CONTROL);
529
 
530
    ModePriv->StoreCrtcCountControl = RHDRegRead(Crtc, RegOff + D1CRTC_COUNT_CONTROL);
531
    RHDDebug(Crtc->scrnIndex, "Saved CrtcCountControl[%i] = 0x%8.8x\n",
532
	     Crtc->Id,ModePriv->StoreCrtcCountControl);
533
 
534
    Crtc->ModePriv = ModePriv;
535
}
536
 
537
/*
538
 *
539
 */
540
static void
541
DxModeRestore(struct rhdCrtc *Crtc)
542
{
543
    struct rhdCrtcModePrivate *ModePriv = Crtc->ModePriv;
544
    CARD32 RegOff;
545
 
546
    if (!ModePriv) {
547
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
548
		   __func__);
549
	return;
550
    }
551
 
552
    if (Crtc->Id == RHD_CRTC_1)
553
	RegOff = D1_REG_OFFSET;
554
    else
555
	RegOff = D2_REG_OFFSET;
556
 
557
    /* ModeSet */
558
    RHDRegWrite(Crtc, RegOff + D1CRTC_CONTROL, ModePriv->StoreCrtcControl);
559
 
560
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, ModePriv->StoreCrtcHTotal);
561
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END,
562
		ModePriv->StoreCrtcHBlankStartEnd);
563
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A, ModePriv->StoreCrtcHSyncA);
564
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, ModePriv->StoreCrtcHSyncACntl);
565
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B, ModePriv->StoreCrtcHSyncB);
566
    RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL, ModePriv->StoreCrtcHSyncBCntl);
567
 
568
    RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, ModePriv->StoreModeDataFormat);
569
    RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, ModePriv->StoreCrtcInterlaceControl);
570
 
571
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, ModePriv->StoreCrtcVTotal);
572
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END,
573
		ModePriv->StoreCrtcVBlankStartEnd);
574
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA);
575
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, ModePriv->StoreCrtcVSyncACntl);
576
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B, ModePriv->StoreCrtcVSyncB);
577
    RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL, ModePriv->StoreCrtcVSyncBCntl);
578
 
579
    RHDRegWrite(Crtc, RegOff + D1CRTC_COUNT_CONTROL, ModePriv->StoreCrtcCountControl);
580
 
581
    /* Blank */
582
    RHDRegWrite(Crtc, RegOff + D1CRTC_BLACK_COLOR, ModePriv->StoreCrtcBlackColor);
583
    RHDRegWrite(Crtc, RegOff + D1CRTC_BLANK_CONTROL, ModePriv->StoreCrtcBlankControl);
584
 
585
    /* When VGA is enabled, it imposes its timing on us, so our CRTC SYNC
586
     * timing can be set to 0. This doesn't always restore properly...
587
     * Workaround is to set a valid sync length for a bit so VGA can
588
     * latch in. */
589
    if (!ModePriv->StoreCrtcVSyncA && (ModePriv->StoreCrtcControl & 0x00000001)) {
590
	RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, 0x00040000);
591
	usleep(300000); /* seems a reliable timeout here */
592
	RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA);
593
    }
594
}
595
 
596
/*
597
 *
598
 */
599
static void
600
DxModeDestroy(struct rhdCrtc *Crtc)
601
{
602
    RHDFUNC(Crtc);
603
 
604
    if (Crtc->ModePriv)
605
	xfree(Crtc->ModePriv);
606
    Crtc->ModePriv = NULL;
607
}
608
 
609
/*
610
 *
611
 */
612
struct rhdScalerOverscan
613
rhdCalculateOverscan(DisplayModePtr Mode, DisplayModePtr ScaledToMode, enum rhdCrtcScaleType Type)
614
{
615
    struct rhdScalerOverscan Overscan;
616
    int tmp;
617
 
618
    Overscan.OverscanTop = Overscan.OverscanBottom = Overscan.OverscanLeft = Overscan.OverscanRight = 0;
619
    Overscan.Type = Type;
620
 
621
    if (ScaledToMode) {
622
	Overscan.OverscanTop = ScaledToMode->CrtcVDisplay - Mode->CrtcVDisplay;
623
	Overscan.OverscanLeft = ScaledToMode->CrtcHDisplay - Mode->CrtcHDisplay;
624
 
625
	if (!Overscan.OverscanTop && !Overscan.OverscanLeft)
626
	    Overscan.Type = RHD_CRTC_SCALE_TYPE_NONE;
627
 
628
	/* handle down scaling */
629
	if (Overscan.OverscanTop < 0) {
630
	    Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
631
	    Overscan.OverscanTop = 0;
632
	}
633
	if (Overscan.OverscanLeft < 0) {
634
	    Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
635
	    Overscan.OverscanLeft = 0;
636
	}
637
    }
638
 
639
    switch (Type) {
640
	case RHD_CRTC_SCALE_TYPE_NONE:
641
	    break;
642
 
643
	case RHD_CRTC_SCALE_TYPE_CENTER:
644
	    tmp = Overscan.OverscanTop;
645
	    Overscan.OverscanTop >>= 1;
646
	    Overscan.OverscanBottom = tmp - Overscan.OverscanTop;
647
	    tmp = Overscan.OverscanLeft;
648
	    Overscan.OverscanLeft >>= 1;
649
	    Overscan.OverscanRight = tmp - Overscan.OverscanLeft;
650
	    break;
651
 
652
	case RHD_CRTC_SCALE_TYPE_SCALE:
653
	    Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0;
654
	    break;
655
	case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO:
656
	{
657
	    int p1, p2, tmp;
658
	    Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0;
659
	    p1 = Mode->CrtcVDisplay * ScaledToMode->CrtcHDisplay;
660
	    p2 = ScaledToMode->CrtcVDisplay * Mode->CrtcHDisplay;
661
	    if (p1 == p2) {
662
		Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE;
663
	    } else if (p1 > p2) {
664
		tmp = (p2 / Mode->CrtcVDisplay);
665
		tmp = ScaledToMode->CrtcHDisplay - tmp;
666
		Overscan.OverscanLeft = tmp >> 1;
667
		Overscan.OverscanRight = tmp - Overscan.OverscanLeft;
668
		ErrorF("HScale %i %i\n", Overscan.OverscanLeft, Overscan.OverscanRight);
669
	    } else {
670
		tmp = (p1 / Mode->CrtcHDisplay);
671
		tmp = ScaledToMode->CrtcVDisplay - tmp;
672
		Overscan.OverscanTop = tmp >> 1;
673
		Overscan.OverscanBottom = tmp - Overscan.OverscanTop;
674
		ErrorF("VScale %i %i\n", Overscan.OverscanTop, Overscan.OverscanBottom);
675
	    }
676
	    break;
677
	}
678
    }
679
 
680
    return Overscan;
681
}
682
 
683
/*
684
 *
685
 */
686
static ModeStatus
687
DxScaleValid(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type,
688
	     DisplayModePtr Mode, DisplayModePtr ScaledToMode)
689
{
690
    struct rhdScalerOverscan Overscan;
691
 
692
    /* D1_MODE_VIEWPORT_WIDTH: 14bits */
693
    if (Mode->CrtcHDisplay >= 0x4000)
694
	return MODE_BAD_HVALUE;
695
 
696
    /* D1_MODE_VIEWPORT_HEIGHT: 14bits */
697
    if (Mode->CrtcVDisplay >= 0x4000)
698
	return MODE_BAD_VVALUE;
699
 
700
    Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type);
701
 
702
    if (Overscan.OverscanLeft >= 4096 || Overscan.OverscanRight >= 4096)
703
	return MODE_HBLANK_WIDE;
704
 
705
    if (Overscan.OverscanTop >= 4096 || Overscan.OverscanBottom >= 4096)
706
	return MODE_VBLANK_WIDE;
707
 
708
    if ((Type == RHD_CRTC_SCALE_TYPE_SCALE
709
	 || Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO)
710
	&& (Mode->Flags & V_INTERLACE))
711
	return MODE_NO_INTERLACE;
712
 
713
    /* should we also fail of Type != Overscan.Type? */
714
 
715
    return MODE_OK;
716
}
717
 
718
/*
719
 *
720
 */
721
static void
722
DxScaleSet(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type,
723
	   DisplayModePtr Mode, DisplayModePtr ScaledToMode)
724
{
725
    RHDPtr rhdPtr = RHDPTRI(Crtc);
726
    CARD16 RegOff;
727
    struct rhdScalerOverscan Overscan;
728
 
729
    RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i\n", __func__, Crtc->Name,
730
	     Mode->CrtcHDisplay, Mode->CrtcVDisplay);
731
 
732
    if (Crtc->Id == RHD_CRTC_1)
733
	RegOff = D1_REG_OFFSET;
734
    else
735
	RegOff = D2_REG_OFFSET;
736
 
737
    Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type);
738
    Type = Overscan.Type;
739
 
740
    RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i - OverScan: T: %i B: %i R: %i L: %i\n",
741
	     __func__, Crtc->Name, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
742
	     Overscan.OverscanTop, Overscan.OverscanBottom,
743
	     Overscan.OverscanLeft, Overscan.OverscanRight);
744
 
745
    /* D1Mode registers */
746
    RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE,
747
		Mode->CrtcVDisplay | (Mode->CrtcHDisplay << 16));
748
    RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, 0);
749
 
750
    RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
751
		(Overscan.OverscanLeft << 16) | Overscan.OverscanRight);
752
    RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
753
		(Overscan.OverscanTop << 16) | Overscan.OverscanBottom);
754
 
755
    switch (Type) {
756
	case RHD_CRTC_SCALE_TYPE_NONE:  /* No scaling whatsoever */
757
	    ErrorF("None\n");
758
	    RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0);
759
	    RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0);
760
	    RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0);
761
	    break;
762
	case RHD_CRTC_SCALE_TYPE_CENTER: /* center of the actual mode */
763
	    ErrorF("Center\n");
764
	    RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0);
765
	    RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0);
766
	    RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1);
767
	    break;
768
	case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: /* scaled to fullscreen */
769
	case RHD_CRTC_SCALE_TYPE_SCALE: /* scaled to fullscreen */
770
	    ErrorF("Full\n");
771
	    if (Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO)
772
		RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1);
773
	    else
774
		RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0);
775
 
776
	    RHDRegWrite(Crtc, RegOff + D1SCL_UPDATE, 0);
777
	    RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0);
778
 
779
	    RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 1);
780
	    RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, 0x00010001); /* both h/v */
781
 
782
	    RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0x00000101);
783
 
784
	    RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, 0x00030100);
785
	    RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, 0x00030100);
786
 
787
	    RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0x00001010);
788
	    break;
789
    }
790
    RHDMCTuneAccessForDisplay(rhdPtr, Crtc->Id, Mode,
791
			      ScaledToMode ? ScaledToMode : Mode);
792
}
793
 
794
/*
795
 *
796
 */
797
static void
798
DxScaleSave(struct rhdCrtc *Crtc)
799
{
800
    struct rhdCrtcScalePrivate *ScalePriv;
801
    CARD32 RegOff;
802
 
803
    if (!Crtc->ScalePriv)
804
	ScalePriv =  xnfcalloc(1, sizeof(struct rhdCrtcScalePrivate));
805
    else
806
	ScalePriv = Crtc->ScalePriv;
807
 
808
    if (Crtc->Id == RHD_CRTC_1)
809
	RegOff = D1_REG_OFFSET;
810
    else
811
	RegOff = D2_REG_OFFSET;
812
 
813
    ScalePriv->StoreModeViewPortSize = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_SIZE);
814
    ScalePriv->StoreModeViewPortStart = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_START);
815
    ScalePriv->StoreModeOverScanH =
816
	RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT);
817
    ScalePriv->StoreModeOverScanV =
818
	RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM);
819
 
820
    ScalePriv->StoreScaleEnable = RHDRegRead(Crtc, RegOff + D1SCL_ENABLE);
821
    ScalePriv->StoreScaleTapControl = RHDRegRead(Crtc, RegOff + D1SCL_TAP_CONTROL);
822
    ScalePriv->StoreModeCenter = RHDRegRead(Crtc, RegOff + D1MODE_CENTER);
823
    ScalePriv->StoreScaleHV = RHDRegRead(Crtc, RegOff + D1SCL_HVSCALE);
824
    ScalePriv->StoreScaleHFilter = RHDRegRead(Crtc, RegOff + D1SCL_HFILTER);
825
    ScalePriv->StoreScaleVFilter = RHDRegRead(Crtc, RegOff + D1SCL_VFILTER);
826
    ScalePriv->StoreScaleDither = RHDRegRead(Crtc, RegOff + D1SCL_DITHER);
827
 
828
    Crtc->ScalePriv = ScalePriv;
829
}
830
 
831
/*
832
 *
833
 */
834
static void
835
DxScaleRestore(struct rhdCrtc *Crtc)
836
{
837
    struct rhdCrtcScalePrivate *ScalePriv = Crtc->ScalePriv;
838
    CARD32 RegOff;
839
 
840
    if (!ScalePriv) {
841
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
842
		   __func__);
843
	return;
844
    }
845
 
846
    if (Crtc->Id == RHD_CRTC_1)
847
	RegOff = D1_REG_OFFSET;
848
    else
849
	RegOff = D2_REG_OFFSET;
850
 
851
    /* ScaleSet */
852
    RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, ScalePriv->StoreModeViewPortSize);
853
 
854
    /* ScaleSet/ViewPortStart */
855
    RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, ScalePriv->StoreModeViewPortStart);
856
 
857
    /* ScaleSet */
858
    RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT,
859
		ScalePriv->StoreModeOverScanH);
860
    RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM,
861
		ScalePriv->StoreModeOverScanV);
862
 
863
    RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, ScalePriv->StoreScaleEnable);
864
    RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, ScalePriv->StoreScaleTapControl);
865
    RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, ScalePriv->StoreModeCenter);
866
    RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, ScalePriv->StoreScaleHV);
867
    RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, ScalePriv->StoreScaleHFilter);
868
    RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, ScalePriv->StoreScaleVFilter);
869
    RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, ScalePriv->StoreScaleDither);
870
}
871
 
872
/*
873
 *
874
 */
875
static void
876
DxScaleDestroy(struct rhdCrtc *Crtc)
877
{
878
    RHDFUNC(Crtc);
879
 
880
    if (Crtc->ScalePriv)
881
	xfree(Crtc->ScalePriv);
882
    Crtc->ScalePriv = NULL;
883
}
884
 
885
/*
886
 *
887
 */
888
static void
889
D1LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT)
890
{
891
    RHDFUNC(Crtc);
892
 
893
    RHDRegWrite(Crtc, D1GRPH_LUT_SEL, LUT->Id & 1);
894
    Crtc->LUT = LUT;
895
}
896
 
897
/*
898
 *
899
 */
900
static void
901
D2LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT)
902
{
903
    RHDFUNC(Crtc);
904
 
905
    RHDRegWrite(Crtc, D2GRPH_LUT_SEL, LUT->Id & 1);
906
    Crtc->LUT = LUT;
907
}
908
 
909
/*
910
 *
911
 */
912
static void
913
DxLUTSave(struct rhdCrtc *Crtc)
914
{
915
    struct rhdCrtcLUTPrivate *LUTPriv;
916
    CARD32 RegOff;
917
 
918
    if (!Crtc->LUTPriv)
919
	LUTPriv =  xnfcalloc(1, sizeof(struct rhdCrtcLUTPrivate));
920
    else
921
	LUTPriv = Crtc->LUTPriv;
922
 
923
    if (Crtc->Id == RHD_CRTC_1)
924
	RegOff = D1_REG_OFFSET;
925
    else
926
	RegOff = D2_REG_OFFSET;
927
 
928
    LUTPriv->StoreGrphLutSel = RHDRegRead(Crtc, RegOff + D1GRPH_LUT_SEL);
929
 
930
    Crtc->LUTPriv = LUTPriv;
931
}
932
 
933
/*
934
 *
935
 */
936
static void
937
DxLUTRestore(struct rhdCrtc *Crtc)
938
{
939
    struct rhdCrtcLUTPrivate *LUTPriv = Crtc->LUTPriv;
940
    CARD32 RegOff;
941
 
942
    if (!LUTPriv) {
943
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n",
944
		   __func__);
945
	return;
946
    }
947
 
948
    if (Crtc->Id == RHD_CRTC_1)
949
	RegOff = D1_REG_OFFSET;
950
    else
951
	RegOff = D2_REG_OFFSET;
952
 
953
    /* LUTSelect */
954
    RHDRegWrite(Crtc, RegOff + D1GRPH_LUT_SEL, LUTPriv->StoreGrphLutSel);
955
}
956
 
957
/*
958
 *
959
 */
960
static void
961
DxLUTDestroy(struct rhdCrtc *Crtc)
962
{
963
    RHDFUNC(Crtc);
964
 
965
    if (Crtc->LUTPriv)
966
	xfree(Crtc->LUTPriv);
967
    Crtc->LUTPriv = NULL;
968
}
969
 
970
/*
971
 *
972
 */
973
static void
974
D1ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y)
975
{
976
    RHDFUNC(Crtc);
977
 
978
    /* not as granular as docs make it seem to be.
979
     * if the lower two bits are set the line buffer might screw up, requiring
980
     * a power cycle. */
981
    X = (X + 0x02) & ~0x03;
982
    Y &= ~0x01;
983
 
984
    RHDRegMask(Crtc, D1SCL_UPDATE, 0x00010000, 0x0001000);
985
    RHDRegWrite(Crtc, D1MODE_VIEWPORT_START, (X << 16) | Y);
986
    RHDRegMask(Crtc, D1SCL_UPDATE, 0, 0x0001000);
987
 
988
    Crtc->X = X;
989
    Crtc->Y = Y;
990
}
991
 
992
/*
993
 *
994
 */
995
static void
996
D2ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y)
997
{
998
    RHDFUNC(Crtc);
999
 
1000
    /* not as granular as docs make it seem to be. */
1001
    X = (X + 0x02) & ~0x03;
1002
    Y &= ~0x01;
1003
 
1004
    RHDRegMask(Crtc, D2SCL_UPDATE, 0x00010000, 0x0001000);
1005
    RHDRegWrite(Crtc, D2MODE_VIEWPORT_START, (X << 16) | Y);
1006
    RHDRegMask(Crtc, D2SCL_UPDATE, 0, 0x0001000);
1007
 
1008
    Crtc->X = X;
1009
    Crtc->Y = Y;
1010
}
1011
 
1012
#define CRTC_SYNC_WAIT 0x100000
1013
/*
1014
 *
1015
 */
1016
static Bool
1017
D1CRTCDisable(struct rhdCrtc *Crtc)
1018
{
1019
    if (RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00000001) {
1020
    CARD32 Control = RHDRegRead(Crtc, D1CRTC_CONTROL);
1021
    int i;
1022
 
1023
	RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x00000301);
1024
	(void)RHDRegRead(Crtc, D1CRTC_CONTROL);
1025
 
1026
    for (i = 0; i < CRTC_SYNC_WAIT; i++)
1027
	    if (!(RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00010000)) {
1028
		RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i);
1029
		RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300);
1030
		return TRUE;
1031
	    }
1032
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR,
1033
		   "%s: Failed to Unsync %s\n", __func__, Crtc->Name);
1034
	RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300);
1035
	return FALSE;
1036
    }
1037
    return TRUE;
1038
}
1039
 
1040
/*
1041
 *
1042
 */
1043
static Bool
1044
D2CRTCDisable(struct rhdCrtc *Crtc)
1045
{
1046
    if (RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00000001) {
1047
    CARD32 Control = RHDRegRead(Crtc, D2CRTC_CONTROL);
1048
    int i;
1049
 
1050
	RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x00000301);
1051
	(void)RHDRegRead(Crtc, D2CRTC_CONTROL);
1052
 
1053
    for (i = 0; i < CRTC_SYNC_WAIT; i++)
1054
	    if (!(RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00010000)) {
1055
		RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i);
1056
		RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300);
1057
		return TRUE;
1058
	    }
1059
	xf86DrvMsg(Crtc->scrnIndex, X_ERROR,
1060
		   "%s: Failed to Unsync %s\n", __func__, Crtc->Name);
1061
	RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300);
1062
	return FALSE;
1063
    }
1064
    return TRUE;
1065
}
1066
 
1067
/*
1068
 *
1069
 */
1070
static Bool
1071
D1Power(struct rhdCrtc *Crtc, int Power)
1072
{
1073
    Bool ret;
1074
    RHDFUNC(Crtc);
1075
 
1076
    switch (Power) {
1077
    case RHD_POWER_ON:
1078
	RHDRegMask(Crtc, D1GRPH_ENABLE, 0x00000001, 0x00000001);
1079
	usleep(2);
1080
	RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x01000000); /* enable read requests */
1081
	RHDRegMask(Crtc, D1CRTC_CONTROL, 1, 1);
1082
	return TRUE;
1083
    case RHD_POWER_RESET:
1084
	RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
1085
	return D1CRTCDisable(Crtc);
1086
    case RHD_POWER_SHUTDOWN:
1087
    default:
1088
	RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
1089
	ret = D1CRTCDisable(Crtc);
1090
	RHDRegMask(Crtc, D1GRPH_ENABLE, 0, 0x00000001);
1091
	return ret;
1092
    }
1093
}
1094
 
1095
/*
1096
 *
1097
 */
1098
static Bool
1099
D2Power(struct rhdCrtc *Crtc, int Power)
1100
{
1101
    Bool ret;
1102
    RHDFUNC(Crtc);
1103
 
1104
    switch (Power) {
1105
    case RHD_POWER_ON:
1106
	RHDRegMask(Crtc, D2GRPH_ENABLE, 0x00000001, 0x00000001);
1107
	usleep(2);
1108
	RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x01000000); /* enable read requests */
1109
	RHDRegMask(Crtc, D2CRTC_CONTROL, 1, 1);
1110
	return TRUE;
1111
    case RHD_POWER_RESET:
1112
	RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
1113
	return D2CRTCDisable(Crtc);
1114
    case RHD_POWER_SHUTDOWN:
1115
    default:
1116
	RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */
1117
	ret = D2CRTCDisable(Crtc);
1118
	RHDRegMask(Crtc, D2GRPH_ENABLE, 0, 0x00000001);
1119
	return ret;
1120
    }
1121
}
1122
 
1123
/*
1124
 * This is quite different from Power. Power disables and enables things,
1125
 * this here makes the hw send out black, and can switch back and forth
1126
 * immediately. Useful for covering up a framebuffer that is not filled
1127
 * in yet.
1128
 */
1129
static void
1130
D1Blank(struct rhdCrtc *Crtc, Bool Blank)
1131
{
1132
    RHDFUNC(Crtc);
1133
 
1134
    RHDRegWrite(Crtc, D1CRTC_BLACK_COLOR, 0);
1135
    if (Blank)
1136
	RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0x00000100, 0x00000100);
1137
    else
1138
	RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0, 0x00000100);
1139
}
1140
 
1141
/*
1142
 *
1143
 */
1144
static void
1145
D2Blank(struct rhdCrtc *Crtc, Bool Blank)
1146
{
1147
    RHDFUNC(Crtc);
1148
 
1149
    RHDRegWrite(Crtc, D2CRTC_BLACK_COLOR, 0);
1150
    if (Blank)
1151
	RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0x00000100, 0x00000100);
1152
    else
1153
	RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0, 0x00000100);
1154
}
1155
 
1156
/*
1157
 *
1158
 */
1159
static void
1160
DxFMTSet(struct rhdCrtc *Crtc, struct rhdFMTDither *FMTDither)
1161
{
1162
    CARD32 RegOff;
1163
    CARD32 fmt_cntl = 0;
1164
 
1165
    RHDFUNC(Crtc);
1166
 
1167
    if (Crtc->Id == RHD_CRTC_1)
1168
	RegOff = FMT1_REG_OFFSET;
1169
    else
1170
	RegOff = FMT2_REG_OFFSET;
1171
 
1172
    if (FMTDither) {
1173
 
1174
	/* set dither depth to 18/24 */
1175
	fmt_cntl = FMTDither->LVDS24Bit
1176
	    ? (RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH)
1177
	    : 0;
1178
	RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, fmt_cntl,
1179
	       RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH);
1180
 
1181
	/* set temporal dither */
1182
	if (FMTDither->LVDSTemporalDither) {
1183
	    fmt_cntl = FMTDither->LVDSGreyLevel ? RV62_FMT_TEMPORAL_LEVEL : 0x0;
1184
	    /* grey level */
1185
	    RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
1186
		       fmt_cntl, RV62_FMT_TEMPORAL_LEVEL);
1187
	    /* turn on temporal dither and reset */
1188
	    RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
1189
		       RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET,
1190
		       RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET);
1191
	    usleep(20);
1192
	    /* turn off reset */
1193
	    RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0x0,
1194
		       RV62_FMT_TEMPORAL_DITHER_RESET);
1195
	}
1196
	/* spatial dither */
1197
	RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL,
1198
		   FMTDither->LVDSSpatialDither ? RV62_FMT_SPATIAL_DITHER_EN : 0,
1199
		   RV62_FMT_SPATIAL_DITHER_EN);
1200
    } else
1201
	RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0);
1202
 
1203
    /* 4:4:4 encoding */
1204
    RHDRegMask(Crtc,  RegOff + RV620_FMT1_CONTROL, 0, RV62_FMT_PIXEL_ENCODING);
1205
    /* disable color clamping */
1206
    RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, 0);
1207
}
1208
 
1209
/*
1210
 *
1211
 */
1212
static void
1213
DxFMTSave(struct rhdCrtc *Crtc)
1214
{
1215
    struct rhdCrtcFMTPrivate *FMTPrivate;
1216
    CARD32 RegOff;
1217
 
1218
    RHDFUNC(Crtc);
1219
 
1220
    if (!Crtc->FMTPriv)
1221
	FMTPrivate = xnfcalloc(sizeof (struct rhdCrtcFMTPrivate),1);
1222
    else
1223
	FMTPrivate = Crtc->FMTPriv;
1224
 
1225
    if (Crtc->Id == RHD_CRTC_1)
1226
	RegOff = FMT1_REG_OFFSET;
1227
    else
1228
	RegOff = FMT2_REG_OFFSET;
1229
 
1230
    FMTPrivate->StoreControl         = RHDRegRead(Crtc, RegOff + RV620_FMT1_CONTROL);
1231
    FMTPrivate->StoreBitDepthControl = RHDRegRead(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL);
1232
    FMTPrivate->StoreClampCntl       = RHDRegRead(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL);
1233
 
1234
    Crtc->FMTPriv = FMTPrivate;
1235
}
1236
 
1237
/*
1238
 *
1239
 */
1240
static void
1241
DxFMTRestore(struct rhdCrtc *Crtc)
1242
{
1243
    struct rhdCrtcFMTPrivate *FMTPrivate = Crtc->FMTPriv;
1244
    CARD32 RegOff;
1245
 
1246
    RHDFUNC(Crtc);
1247
 
1248
    if (!FMTPrivate)
1249
	return;
1250
 
1251
    if (Crtc->Id == RHD_CRTC_1)
1252
	RegOff = FMT1_REG_OFFSET;
1253
    else
1254
	RegOff = FMT2_REG_OFFSET;
1255
 
1256
    RHDRegWrite(Crtc, RegOff + RV620_FMT1_CONTROL, FMTPrivate->StoreControl);
1257
    RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, FMTPrivate->StoreBitDepthControl);
1258
    RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, FMTPrivate->StoreClampCntl);
1259
}
1260
 
1261
/*
1262
 *
1263
 */
1264
static void
1265
DxFMTDestroy(struct rhdCrtc *Crtc)
1266
{
1267
    RHDFUNC(Crtc);
1268
 
1269
    if (Crtc->FMTPriv)
1270
	xfree(Crtc->FMTPriv);
1271
    Crtc->FMTPriv = NULL;
1272
}
1273
 
1274
/*
1275
 *
1276
 */
1277
static enum rhdCrtcScaleType
1278
rhdInitScaleType(RHDPtr rhdPtr)
1279
{
1280
    RHDFUNC(rhdPtr);
1281
/*
1282
    if (rhdPtr->scaleTypeOpt.set) {
1283
	if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "none"))
1284
	    return RHD_CRTC_SCALE_TYPE_NONE;
1285
	else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "center"))
1286
	    return RHD_CRTC_SCALE_TYPE_CENTER;
1287
	else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale"))
1288
	    return RHD_CRTC_SCALE_TYPE_SCALE;
1289
	else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale_keep_aspect_ratio"))
1290
	    return RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO;
1291
	else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "default"))
1292
	    return RHD_CRTC_SCALE_TYPE_DEFAULT;
1293
	else {
1294
	    xf86DrvMsgVerb(rhdPtr->scrnIndex, X_ERROR, 0,
1295
			   "Unknown scale type: %s\n", rhdPtr->scaleTypeOpt.val.string);
1296
	    return RHD_CRTC_SCALE_TYPE_DEFAULT;
1297
	}
1298
    } else  */
1299
  return RHD_CRTC_SCALE_TYPE_SCALE;
1300
}
1301
 
1302
/*
1303
 *
1304
 */
1305
Bool
1306
RHDCrtcsInit(RHDPtr rhdPtr)
1307
{
1308
    struct rhdCrtc *Crtc;
1309
    enum rhdCrtcScaleType ScaleType;
1310
    Bool useAtom;
1311
 
1312
    RHDFUNC(rhdPtr);
1313
 
1314
    useAtom = RHDUseAtom(rhdPtr, NULL, atomUsageCrtc);
1315
 
1316
    ScaleType = rhdInitScaleType(rhdPtr);
1317
 
1318
    Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1);
1319
    Crtc->scrnIndex = rhdPtr->scrnIndex;
1320
    Crtc->Name = "CRTC 1";
1321
    Crtc->Id = RHD_CRTC_1;
1322
 
1323
    Crtc->ScaleType = ScaleType;
1324
 
1325
    if (rhdPtr->ChipSet >= RHD_RV620) {
1326
	Crtc->FMTDestroy = DxFMTDestroy;
1327
	Crtc->FMTSave = DxFMTSave;
1328
	Crtc->FMTRestore = DxFMTRestore;
1329
	Crtc->FMTModeSet = DxFMTSet;
1330
    }
1331
    Crtc->FMTPriv = NULL;
1332
 
1333
    Crtc->FBValid   = DxFBValid;
1334
    Crtc->FBSet     = DxFBSet;
1335
    Crtc->FBSave = DxFBSave;
1336
    Crtc->FBRestore = DxFBRestore;
1337
    Crtc->FBDestroy = DxFBDestroy;
1338
 
1339
    Crtc->ModeValid = DxModeValid;
1340
    Crtc->ModeSet   = DxModeSet;
1341
    Crtc->ModeSave = DxModeSave;
1342
    Crtc->ModeRestore = DxModeRestore;
1343
    Crtc->ModeDestroy = DxModeDestroy;
1344
    Crtc->ModePriv = NULL;
1345
 
1346
    Crtc->ScaleValid = DxScaleValid;
1347
    Crtc->ScaleSet = DxScaleSet;
1348
    Crtc->ScaleSave = DxScaleSave;
1349
    Crtc->ScaleRestore = DxScaleRestore;
1350
    Crtc->ScaleDestroy = DxScaleDestroy;
1351
    Crtc->ScalePriv = NULL;
1352
 
1353
    Crtc->LUTSelect = D1LUTSelect;
1354
    Crtc->LUTSave = DxLUTSave;
1355
    Crtc->LUTRestore = DxLUTRestore;
1356
    Crtc->LUTDestroy = DxLUTDestroy;
1357
    Crtc->LUTPriv = NULL;
1358
 
1359
    Crtc->FrameSet  = D1ViewPortStart;
1360
 
1361
    Crtc->Power     = D1Power;
1362
    Crtc->Blank     = D1Blank;
1363
 
1364
    rhdPtr->Crtc[0] = Crtc;
1365
 
1366
    Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1);
1367
    Crtc->scrnIndex = rhdPtr->scrnIndex;
1368
    Crtc->Name      = "CRTC 2";
1369
    Crtc->Id        = RHD_CRTC_2;
1370
 
1371
    Crtc->ScaleType = ScaleType;
1372
 
1373
    if (rhdPtr->ChipSet >= RHD_RV620) {
1374
	Crtc->FMTDestroy = DxFMTDestroy;
1375
	Crtc->FMTSave = DxFMTSave;
1376
	Crtc->FMTRestore = DxFMTRestore;
1377
	Crtc->FMTModeSet = DxFMTSet;
1378
    }
1379
    Crtc->FMTPriv = NULL;
1380
 
1381
    Crtc->FBValid   = DxFBValid;
1382
    Crtc->FBSet     = DxFBSet;
1383
    Crtc->FBSave = DxFBSave;
1384
    Crtc->FBRestore = DxFBRestore;
1385
    Crtc->FBDestroy = DxFBDestroy;
1386
 
1387
    Crtc->ModeValid = DxModeValid;
1388
    Crtc->ModeSet   = DxModeSet;
1389
    Crtc->ModeSave = DxModeSave;
1390
    Crtc->ModeRestore = DxModeRestore;
1391
    Crtc->ModeDestroy = DxModeDestroy;
1392
    Crtc->ModePriv = NULL;
1393
 
1394
    Crtc->ScaleValid = DxScaleValid;
1395
    Crtc->ScaleSet = DxScaleSet;
1396
    Crtc->ScaleSave = DxScaleSave;
1397
    Crtc->ScaleRestore = DxScaleRestore;
1398
    Crtc->ScaleDestroy = DxScaleDestroy;
1399
    Crtc->ScalePriv = NULL;
1400
 
1401
    Crtc->LUTSelect = D2LUTSelect;
1402
    Crtc->LUTSave = DxLUTSave;
1403
    Crtc->LUTRestore = DxLUTRestore;
1404
    Crtc->LUTDestroy = DxLUTDestroy;
1405
    Crtc->LUTPriv = NULL;
1406
 
1407
    Crtc->FrameSet  = D2ViewPortStart;
1408
 
1409
    Crtc->Power     = D2Power;
1410
    Crtc->Blank     = D2Blank;
1411
 
1412
    rhdPtr->Crtc[1] = Crtc;
1413
 
1414
    return !useAtom;
1415
}
1416
 
1417
/*
1418
 *
1419
 */
1420
void
1421
RHDCrtcsDestroy(RHDPtr rhdPtr)
1422
{
1423
    struct rhdCrtc *Crtc;
1424
    int i;
1425
 
1426
    RHDFUNC(rhdPtr);
1427
 
1428
    for (i = 0; i < 2; i++) {
1429
	Crtc = rhdPtr->Crtc[i];
1430
    if (Crtc) {
1431
	    if (Crtc->FMTDestroy)
1432
		Crtc->FMTDestroy(Crtc);
1433
 
1434
	    if (Crtc->LUTDestroy)
1435
		Crtc->LUTDestroy(Crtc);
1436
 
1437
	    if (Crtc->FBDestroy)
1438
		Crtc->FBDestroy(Crtc);
1439
 
1440
	    if (Crtc->ScaleDestroy)
1441
		Crtc->ScaleDestroy(Crtc);
1442
 
1443
	    if (Crtc->ModeDestroy)
1444
		Crtc->ModeDestroy(Crtc);
1445
 
1446
	    xfree(Crtc);
1447
	    rhdPtr->Crtc[i] = NULL;
1448
	}
1449
    }
1450
}
1451
 
1452
 
1453
/*
1454
 *
1455
 */
1456
void
1457
RHDCrtcSave(struct rhdCrtc *Crtc)
1458
{
1459
    RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
1460
 
1461
    if (Crtc->FMTSave)
1462
	Crtc->FMTSave(Crtc);
1463
 
1464
    if (Crtc->FBSave)
1465
	Crtc->FBSave(Crtc);
1466
 
1467
    if (Crtc->LUTSave)
1468
	Crtc->LUTSave(Crtc);
1469
 
1470
    if (Crtc->ScaleSave)
1471
	Crtc->ScaleSave(Crtc);
1472
 
1473
    if (Crtc->ModeSave)
1474
	Crtc->ModeSave(Crtc);
1475
}
1476
 
1477
/*
1478
 *
1479
 */
1480
void
1481
RHDCrtcRestore(struct rhdCrtc *Crtc)
1482
{
1483
 
1484
    RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name);
1485
 
1486
    if (Crtc->FMTRestore)
1487
	Crtc->FMTRestore(Crtc);
1488
 
1489
    if (Crtc->FBRestore)
1490
	Crtc->FBRestore(Crtc);
1491
 
1492
    if (Crtc->LUTRestore)
1493
	Crtc->LUTRestore(Crtc);
1494
 
1495
    if (Crtc->ScaleRestore)
1496
	Crtc->ScaleRestore(Crtc);
1497
 
1498
    if (Crtc->ModeRestore)
1499
	Crtc->ModeRestore(Crtc);
1500
}